diff --git a/Server/application/chukebao/controller/MessageController.php b/Server/application/chukebao/controller/MessageController.php index 7d626e59..3f8c9cfe 100644 --- a/Server/application/chukebao/controller/MessageController.php +++ b/Server/application/chukebao/controller/MessageController.php @@ -7,6 +7,7 @@ use app\chukebao\model\FriendSettings; use library\ResponseHelper; use think\Db; use think\facade\Env; +use think\facade\Cache; use app\common\service\AuthService; class MessageController extends BaseController @@ -30,174 +31,221 @@ class MessageController extends BaseController return ResponseHelper::error('请先登录'); } - $friends = Db::table('s2_wechat_friend') - ->where(['accountId' => $accountId, 'isDeleted' => 0]) - ->column('id,nickname,avatar,conRemark,labels,groupId,wechatAccountId,wechatId,extendFields,phone,region,isTop'); + // 缓存键 + $cacheKeyFriends = 'message_list_friends_' . $accountId; + $cacheKeyChatrooms = 'message_list_chatrooms_' . $accountId; + $cacheKeyMessages = 'message_list_messages_' . $accountId; + + // 缓存时间:好友和群聊信息5分钟,消息列表30秒 + $cacheTimeFriends = 300; // 5分钟 + $cacheTimeChatrooms = 300; // 5分钟 + $cacheTimeMessages = 30; // 30秒 + // 从缓存获取好友ID列表 + $friendIds = Cache::get($cacheKeyFriends . '_ids'); + if ($friendIds === false) { + $ids = Db::table('s2_wechat_friend') + ->where(['accountId' => $accountId, 'isDeleted' => 0]) + ->column('id'); + $friendIds = empty($ids) ? [0] : $ids; // 避免 IN 查询为空 + Cache::set($cacheKeyFriends . '_ids', $friendIds, $cacheTimeFriends); + } - // 构建好友子查询 - $friendSubQuery = Db::table('s2_wechat_friend') - ->where(['accountId' => $accountId, 'isDeleted' => 0]) - ->field('id') - ->buildSql(); + // 从缓存获取好友信息 + $friends = Cache::get($cacheKeyFriends); + if ($friends === false) { + $friends = Db::table('s2_wechat_friend') + ->where(['accountId' => $accountId, 'isDeleted' => 0]) + ->column('id,nickname,avatar,conRemark,labels,groupId,wechatAccountId,wechatId,extendFields,phone,region,isTop'); + Cache::set($cacheKeyFriends, $friends, $cacheTimeFriends); + } - // 计算总数:群聊数量 + 好友数量 - // 使用与 UNION 查询相同的逻辑来计算总数 - $countQuery = " - SELECT COUNT(*) as total FROM ( - (SELECT DISTINCT wc.id - FROM s2_wechat_chatroom wc - INNER JOIN s2_wechat_message m ON wc.id = m.wechatChatroomId AND m.type = 2 - INNER JOIN ( - SELECT wechatChatroomId, MAX(wechatTime) as maxTime, MAX(id) as maxId - FROM s2_wechat_message - WHERE type = 2 - GROUP BY wechatChatroomId - ) latest ON m.wechatChatroomId = latest.wechatChatroomId AND m.wechatTime = latest.maxTime AND m.id = latest.maxId - WHERE wc.accountId = {$accountId} AND wc.isDeleted = 0 - ) - UNION ALL - (SELECT DISTINCT m.wechatFriendId as id - FROM s2_wechat_message m - INNER JOIN ( - SELECT wechatFriendId, MAX(wechatTime) as maxTime, MAX(id) as maxId - FROM s2_wechat_message - WHERE type = 1 AND wechatFriendId IN {$friendSubQuery} - GROUP BY wechatFriendId - ) latest ON m.wechatFriendId = latest.wechatFriendId AND m.wechatTime = latest.maxTime AND m.id = latest.maxId - WHERE m.type = 1 AND m.wechatFriendId IN {$friendSubQuery} - ) - ) as combined - "; - $totalResult = Db::query($countQuery); - $total = !empty($totalResult) ? (int)$totalResult[0]['total'] : 0; + // 从缓存获取群聊信息 + $chatrooms = Cache::get($cacheKeyChatrooms); + if ($chatrooms === false) { + $chatrooms = Db::table('s2_wechat_chatroom') + ->where(['accountId' => $accountId, 'isDeleted' => 0]) + ->column('id,nickname,chatroomAvatar,chatroomId,isTop'); + Cache::set($cacheKeyChatrooms, $chatrooms, $cacheTimeChatrooms); + } - // 优化后的查询:使用MySQL兼容的查询方式 - $unionQuery = " - (SELECT m.id, m.content, m.wechatFriendId, m.wechatChatroomId, m.createTime, m.wechatTime,m.wechatAccountId, 2 as msgType, wc.nickname, wc.chatroomAvatar as avatar, wc.chatroomId, wc.isTop - FROM s2_wechat_chatroom wc - INNER JOIN s2_wechat_message m ON wc.id = m.wechatChatroomId AND m.type = 2 - INNER JOIN ( - SELECT wechatChatroomId, MAX(wechatTime) as maxTime, MAX(id) as maxId - FROM s2_wechat_message - WHERE type = 2 - GROUP BY wechatChatroomId - ) latest ON m.wechatChatroomId = latest.wechatChatroomId AND m.wechatTime = latest.maxTime AND m.id = latest.maxId - WHERE wc.accountId = {$accountId} AND wc.isDeleted = 0 - ) - UNION ALL - (SELECT m.id, m.content, m.wechatFriendId, m.wechatChatroomId, m.createTime, m.wechatTime, 1 as msgType, 1 as nickname, 1 as avatar, 1 as chatroomId, 1 as wechatAccountId, 0 as isTop - FROM s2_wechat_message m - INNER JOIN ( - SELECT wechatFriendId, MAX(wechatTime) as maxTime, MAX(id) as maxId - FROM s2_wechat_message - WHERE type = 1 AND wechatFriendId IN {$friendSubQuery} - GROUP BY wechatFriendId - ) latest ON m.wechatFriendId = latest.wechatFriendId AND m.wechatTime = latest.maxTime AND m.id = latest.maxId - WHERE m.type = 1 AND m.wechatFriendId IN {$friendSubQuery} - ) - ORDER BY wechatTime DESC - LIMIT " . (($page - 1) * $limit) . ", {$limit} - "; + // 优化:分别查询群聊和好友的最新消息,使用缓存 + // 从缓存获取最新消息列表(短时间缓存,保证消息实时性) + $allMessages = Cache::get($cacheKeyMessages); + if ($allMessages === false) { + // 获取群聊ID列表 + $chatroomIds = array_keys($chatrooms); + if (empty($chatroomIds)) { + $chatroomIds = [0]; + } + + // 1. 查询群聊最新消息 + $chatroomMessages = []; + if (!empty($chatroomIds) && $chatroomIds[0] != 0) { + $chatroomIdsStr = implode(',', array_map('intval', $chatroomIds)); + $chatroomLatestQuery = " + SELECT wc.id as chatroomId, m.id, m.content, m.wechatChatroomId, m.createTime, m.wechatTime, m.wechatAccountId, + wc.nickname, wc.chatroomAvatar as avatar, wc.chatroomId, wc.isTop, 2 as msgType + FROM s2_wechat_chatroom wc + INNER JOIN ( + SELECT wechatChatroomId, MAX(wechatTime) as maxTime, MAX(id) as maxId + FROM s2_wechat_message + WHERE type = 2 AND wechatChatroomId IN ({$chatroomIdsStr}) + GROUP BY wechatChatroomId + ) latest ON wc.id = latest.wechatChatroomId + INNER JOIN s2_wechat_message m ON m.wechatChatroomId = latest.wechatChatroomId + AND m.wechatTime = latest.maxTime AND m.id = latest.maxId + WHERE wc.accountId = {$accountId} AND wc.isDeleted = 0 + "; + $chatroomMessages = Db::query($chatroomLatestQuery); + } - $list = Db::query($unionQuery); + // 2. 查询好友最新消息 + $friendMessages = []; + if (!empty($friendIds) && $friendIds[0] != 0) { + $friendIdsStr = implode(',', array_map('intval', $friendIds)); + $friendLatestQuery = " + SELECT m.wechatFriendId, m.id, m.content, m.createTime, m.wechatTime, + f.wechatAccountId, 1 as msgType, 0 as isTop + FROM s2_wechat_message m + INNER JOIN ( + SELECT wechatFriendId, MAX(wechatTime) as maxTime, MAX(id) as maxId + FROM s2_wechat_message + WHERE type = 1 AND wechatFriendId IN ({$friendIdsStr}) + GROUP BY wechatFriendId + ) latest ON m.wechatFriendId = latest.wechatFriendId + AND m.wechatTime = latest.maxTime AND m.id = latest.maxId + INNER JOIN s2_wechat_friend f ON f.id = m.wechatFriendId + WHERE m.type = 1 AND m.wechatFriendId IN ({$friendIdsStr}) + "; + $friendMessages = Db::query($friendLatestQuery); + } - // 对分页后的结果进行排序(按wechatTime降序) - usort($list, function ($a, $b) { - return $b['wechatTime'] <=> $a['wechatTime']; - }); + // 合并结果并排序 + $allMessages = array_merge($chatroomMessages, $friendMessages); + usort($allMessages, function ($a, $b) { + return $b['wechatTime'] <=> $a['wechatTime']; + }); + + // 存入缓存 + Cache::set($cacheKeyMessages, $allMessages, $cacheTimeMessages); + } - // 批量统计未读数量(isRead=0),按好友/群聊分别聚合 - $friendIds = []; - $chatroomIds = []; + // 计算总数 + $totalCount = count($allMessages); + + // 分页处理 + $list = array_slice($allMessages, ($page - 1) * $limit, $limit); + + // 收集需要查询的ID + $queryFriendIds = []; + $queryChatroomIds = []; foreach ($list as $row) { if (!empty($row['wechatFriendId'])) { - $friendIds[] = $row['wechatFriendId']; + $queryFriendIds[] = $row['wechatFriendId']; } if (!empty($row['wechatChatroomId'])) { - $chatroomIds[] = $row['wechatChatroomId']; + $queryChatroomIds[] = $row['wechatChatroomId']; } } - $friendIds = array_values(array_unique(array_filter($friendIds))); - $chatroomIds = array_values(array_unique(array_filter($chatroomIds))); + $queryFriendIds = array_unique($queryFriendIds); + $queryChatroomIds = array_unique($queryChatroomIds); - $friendUnreadMap = []; - if (!empty($friendIds)) { - // 获取未读消息数量 - $friendUnreadMap = Db::table('s2_wechat_message') - ->where(['isRead' => 0]) - ->whereIn('wechatFriendId', $friendIds) + // 批量查询未读数量(优化:合并查询) + $unreadMap = []; + if (!empty($queryFriendIds)) { + $friendUnreads = Db::table('s2_wechat_message') + ->where(['isRead' => 0, 'type' => 1]) + ->whereIn('wechatFriendId', $queryFriendIds) + ->field('wechatFriendId, COUNT(*) as cnt') ->group('wechatFriendId') - ->column('COUNT(*) AS cnt', 'wechatFriendId'); + ->select(); + foreach ($friendUnreads as $item) { + $unreadMap['friend_' . $item['wechatFriendId']] = (int)$item['cnt']; + } } - $chatroomUnreadMap = []; - if (!empty($chatroomIds)) { - // 获取未读消息数量 - $chatroomUnreadMap = Db::table('s2_wechat_message') - ->where(['isRead' => 0]) - ->whereIn('wechatChatroomId', $chatroomIds) + if (!empty($queryChatroomIds)) { + $chatroomUnreads = Db::table('s2_wechat_message') + ->where(['isRead' => 0, 'type' => 2]) + ->whereIn('wechatChatroomId', $queryChatroomIds) + ->field('wechatChatroomId, COUNT(*) as cnt') ->group('wechatChatroomId') - ->column('COUNT(*) AS cnt', 'wechatChatroomId'); + ->select(); + foreach ($chatroomUnreads as $item) { + $unreadMap['chatroom_' . $item['wechatChatroomId']] = (int)$item['cnt']; + } } + // 批量查询AI类型 $aiTypeData = []; - if (!empty($friendIds)) { - $aiTypeData = FriendSettings::where('friendId', 'in', $friendIds)->column('friendId,type'); + if (!empty($queryFriendIds)) { + $aiTypeData = FriendSettings::where('friendId', 'in', $queryFriendIds)->column('friendId,type'); } + // 格式化数据 foreach ($list as $k => &$v) { - $createTime = !empty($v['createTime']) ? date('Y-m-d H:i:s', $v['createTime']) : ''; $wechatTime = !empty($v['wechatTime']) ? date('Y-m-d H:i:s', $v['wechatTime']) : ''; - $unreadCount = 0; $v['aiType'] = 0; + if (!empty($v['wechatFriendId'])) { - $v['nickname'] = !empty($friends[$v['wechatFriendId']]) ? $friends[$v['wechatFriendId']]['nickname'] : ''; - $v['avatar'] = !empty($friends[$v['wechatFriendId']]) ? $friends[$v['wechatFriendId']]['avatar'] : ''; - $v['conRemark'] = !empty($friends[$v['wechatFriendId']]) ? $friends[$v['wechatFriendId']]['conRemark'] : ''; - $v['groupId'] = !empty($friends[$v['wechatFriendId']]) ? $friends[$v['wechatFriendId']]['groupId'] : ''; - $v['wechatAccountId'] = !empty($friends[$v['wechatFriendId']]) ? $friends[$v['wechatFriendId']]['wechatAccountId'] : ''; - $v['wechatId'] = !empty($friends[$v['wechatFriendId']]) ? $friends[$v['wechatFriendId']]['wechatId'] : ''; - $v['extendFields'] = !empty($friends[$v['wechatFriendId']]) ? $friends[$v['wechatFriendId']]['extendFields'] : []; - $v['region'] = !empty($friends[$v['wechatFriendId']]) ? $friends[$v['wechatFriendId']]['region'] : ''; - $v['phone'] = !empty($friends[$v['wechatFriendId']]) ? $friends[$v['wechatFriendId']]['phone'] : ''; - $v['isTop'] = !empty($friends[$v['wechatFriendId']]) ? $friends[$v['wechatFriendId']]['isTop'] : 0; - $v['labels'] = !empty($friends[$v['wechatFriendId']]) ? json_decode($friends[$v['wechatFriendId']]['labels'], true) : []; + // 好友消息 + $friendId = $v['wechatFriendId']; + $friend = $friends[$friendId] ?? null; + + $v['nickname'] = $friend['nickname'] ?? ''; + $v['avatar'] = $friend['avatar'] ?? ''; + $v['conRemark'] = $friend['conRemark'] ?? ''; + $v['groupId'] = $friend['groupId'] ?? ''; + $v['wechatAccountId'] = $friend['wechatAccountId'] ?? ''; + $v['wechatId'] = $friend['wechatId'] ?? ''; + $v['extendFields'] = $friend['extendFields'] ?? []; + $v['region'] = $friend['region'] ?? ''; + $v['phone'] = $friend['phone'] ?? ''; + $v['isTop'] = $friend['isTop'] ?? 0; + $v['labels'] = !empty($friend['labels']) ? json_decode($friend['labels'], true) : []; - $unreadCount = isset($friendUnreadMap[$v['wechatFriendId']]) ? (int)$friendUnreadMap[$v['wechatFriendId']] : 0; - $v['aiType'] = isset($aiTypeData[$v['wechatFriendId']]) ? $aiTypeData[$v['wechatFriendId']] : 0; + $unreadCount = $unreadMap['friend_' . $friendId] ?? 0; + $v['aiType'] = $aiTypeData[$friendId] ?? 0; + $v['id'] = $friendId; unset($v['chatroomId']); - } - - if (!empty($v['wechatChatroomId'])) { + } elseif (!empty($v['wechatChatroomId'])) { + // 群聊消息 + $chatroomId = $v['wechatChatroomId']; + $chatroom = $chatrooms[$chatroomId] ?? null; + + $v['nickname'] = $chatroom['nickname'] ?? ''; + $v['avatar'] = $chatroom['chatroomAvatar'] ?? ''; $v['conRemark'] = ''; - $unreadCount = isset($chatroomUnreadMap[$v['wechatChatroomId']]) ? (int)$chatroomUnreadMap[$v['wechatChatroomId']] : 0; + $v['isTop'] = $chatroom['isTop'] ?? 0; + $v['chatroomId'] = $chatroom['chatroomId'] ?? ''; + + $unreadCount = $unreadMap['chatroom_' . $chatroomId] ?? 0; + $v['id'] = $chatroomId; + unset($v['wechatFriendId']); } - $v['id'] = !empty($v['wechatFriendId']) ? $v['wechatFriendId'] : $v['wechatChatroomId']; $v['config'] = [ 'top' => !empty($v['isTop']) ? true : false, 'unreadCount' => $unreadCount, 'chat' => true, - 'msgTime' => $v['wechatTime'], + 'msgTime' => $wechatTime, ]; $v['createTime'] = $createTime; $v['lastUpdateTime'] = $wechatTime; - - // 最新消息内容已经在UNION查询中获取,直接使用 $v['latestMessage'] = [ - 'content' => $v['content'], + 'content' => $v['content'] ?? '', 'wechatTime' => $wechatTime ]; - unset($v['wechatFriendId'], $v['wechatChatroomId'],$v['isTop']); - + unset($v['wechatChatroomId'], $v['isTop'], $v['msgType']); } unset($v); - return ResponseHelper::success(['list' => $list, 'total' => $total]); + + return ResponseHelper::success(['list' => $list, 'total' => $totalCount]); }