Files
p_ysk/app/chat/controller/MessageController.php
2025-11-18 09:37:05 +08:00

261 lines
8.5 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<?php
namespace app\chat\controller;
use app\chat\model\ChatMessage;
use app\chat\model\ChatUnreadCount;
use app\chat\model\ChatTop;
use app\chat\model\ChatUser;
use app\chat\model\ChatGroup;
use app\utils\Session;
use support\Request;
use support\Response;
class MessageController
{
/**
* 获取历史消息
*/
public function history(Request $request): Response
{
$uid = $request->uid;
$chatType = $request->get('chat_type', 1); // 1=单聊2=群聊
$toId = $request->get('to_id', 0); // 单聊=对方ID群聊=群ID
$page = $request->get('page', 1);
$size = $request->get('size', 20);
if (!$toId) {
return json(['code' => 400, 'msg' => '缺少to_id']);
}
// 生成会话ID
$sessionId = Session::generateSessionId($chatType, $uid, $toId);
// 构建查询条件
$query = ChatMessage::where('session_id', $sessionId);
// 群聊需验证是否在群内
if ($chatType == 2) {
$isMember = app\chat\model\ChatGroupMember::where([
'group_id' => $toId,
'user_id' => $uid,
'quit_time' => null,
'is_kicked' => 0
])->exists();
if (!$isMember) {
return json(['code' => 403, 'msg' => '不在群内,无法获取历史消息']);
}
}
// 分页查询(倒序取,再正序返回)
$total = $query->count();
$messages = $query->orderBy('send_time', 'desc')
->page($page, $size)
->get()
->toArray();
$messages = array_reverse($messages);
// 单聊自动标记已读
if ($chatType == 1) {
ChatMessage::where([
'session_id' => $sessionId,
'to_id' => $uid,
'is_read' => 0
])->update(['is_read' => 1]);
// 重置未读计数
ChatUnreadCount::where([
'user_id' => $uid,
'session_id' => $sessionId
])->update(['count' => 0, 'updated_at' => time()]);
}
return json([
'code' => 200,
'msg' => 'success',
'data' => [
'list' => $messages,
'page' => $page,
'size' => $size,
'total' => $total
]
]);
}
/**
* 标记消息已读(批量)
*/
public function markRead(Request $request): Response
{
$uid = $request->uid;
$msgIds = $request->post('msg_ids', []);
if (empty($msgIds) || !is_array($msgIds)) {
return json(['code' => 400, 'msg' => '请传入有效消息ID数组']);
}
// 标记已读(仅自己接收的消息)
$messages = ChatMessage::whereIn('id', $msgIds)
->where('to_id', $uid)
->where('is_read', 0)
->get();
if (empty($messages)) {
return json(['code' => 200, 'msg' => '无未读消息可标记']);
}
// 批量更新
$sessionIds = $messages->pluck('session_id')->unique()->toArray();
ChatMessage::whereIn('id', $msgIds)->where('to_id', $uid)->update(['is_read' => 1]);
// 更新未读计数
foreach ($sessionIds as $sessionId) {
$reduceNum = ChatMessage::whereIn('id', $msgIds)
->where('session_id', $sessionId)
->count();
$unread = ChatUnreadCount::where(['user_id' => $uid, 'session_id' => $sessionId])->first();
if ($unread) {
$newCount = max(0, $unread->count - $reduceNum);
$unread->count = $newCount;
$unread->updated_at = time();
$unread->save();
}
}
return json(['code' => 200, 'msg' => '标记已读成功']);
}
/**
* 标记会话全部已读
*/
public function markReadAll(Request $request): Response
{
$uid = $request->uid;
$sessionId = $request->post('session_id', '');
if (empty($sessionId)) {
return json(['code' => 400, 'msg' => '缺少session_id']);
}
// 标记该会话所有未读消息已读
ChatMessage::where([
'session_id' => $sessionId,
'to_id' => $uid,
'is_read' => 0
])->update(['is_read' => 1]);
// 重置未读计数
ChatUnreadCount::where([
'user_id' => $uid,
'session_id' => $sessionId
])->update(['count' => 0, 'updated_at' => time()]);
return json(['code' => 200, 'msg' => '标记全部已读成功']);
}
/**
* 获取未读消息总数
*/
public function getUnreadCount(Request $request): Response
{
$uid = $request->uid;
$total = ChatUnreadCount::where('user_id', $uid)->sum('count');
return json(['code' => 200, 'msg' => 'success', 'data' => ['total' => $total]]);
}
/**
* 获取会话列表(含置顶、未读、最后消息)
*/
public function getSessionList(Request $request): Response
{
$uid = $request->uid;
// 获取所有会话ID
$sessionIds = ChatMessage::where(function ($query) use ($uid) {
$query->where('from_id', $uid)->orWhere('to_id', $uid);
})->groupBy('session_id')->pluck('session_id')->toArray();
if (empty($sessionIds)) {
return json(['code' => 200, 'msg' => 'success', 'data' => ['list' => []]]);
}
$sessionList = [];
foreach ($sessionIds as $sessionId) {
// 置顶状态
$top = ChatTop::where(['user_id' => $uid, 'session_id' => $sessionId])->first();
$isTop = $top && $top->status == 1 ? 1 : 0;
$sort = $top ? $top->sort : 0;
// 未读计数
$unread = ChatUnreadCount::where(['user_id' => $uid, 'session_id' => $sessionId])->first();
$unreadCount = $unread ? $unread->count : 0;
// 最后一条消息
$lastMsg = ChatMessage::where('session_id', $sessionId)
->orderBy('send_time', 'desc')
->first([
'id', 'from_id', 'msg_type', 'content', 'image_url',
'order_id', 'send_time', 'is_read'
]);
if (!$lastMsg) continue;
// 会话类型(单聊/群聊)
$chatType = strpos($sessionId, 'group_') === 0 ? 2 : 1;
$targetInfo = [];
if ($chatType == 1) {
// 单聊解析对方ID
list($minId, $maxId) = explode('_', $sessionId);
$targetUid = $uid == $minId ? $maxId : $minId;
$targetUser = ChatUser::find($targetUid);
if ($targetUser) {
$targetInfo = [
'id' => $targetUser->id,
'name' => $targetUser->username,
'avatar' => $targetUser->avatar,
'type' => $targetUser->type
];
}
} else {
// 群聊解析群ID
$groupId = str_replace('group_', '', $sessionId);
$group = ChatGroup::find($groupId);
if ($group) {
$targetInfo = [
'id' => $group->id,
'name' => $group->name,
'avatar' => $group->avatar,
'owner_id' => $group->owner_id
];
}
}
$sessionList[] = [
'session_id' => $sessionId,
'chat_type' => $chatType,
'is_top' => $isTop,
'sort' => $sort,
'unread_count' => $unreadCount,
'last_msg' => $lastMsg ? $lastMsg->toArray() : [],
'target_info' => $targetInfo
];
}
// 排序置顶按sort降序→ 非置顶(按最后消息时间降序)
usort($sessionList, function ($a, $b) {
if ($a['is_top'] != $b['is_top']) {
return $b['is_top'] - $a['is_top'];
}
if ($a['is_top'] == 1) {
return $b['sort'] - $a['sort'];
}
$aTime = $a['last_msg']['send_time'] ?? 0;
$bTime = $b['last_msg']['send_time'] ?? 0;
return $bTime - $aTime;
});
return json(['code' => 200, 'msg' => 'success', 'data' => ['list' => $sessionList]]);
}
}