261 lines
8.5 KiB
PHP
261 lines
8.5 KiB
PHP
<?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]]);
|
||
}
|
||
}
|