This commit is contained in:
wong
2026-01-12 17:02:31 +08:00
parent 80ae205cb3
commit 9eeaaa70c4

View File

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