214 lines
7.0 KiB
PHP
214 lines
7.0 KiB
PHP
<?php
|
|
// +----------------------------------------------------------------------
|
|
// | YwxApp [ WE CAN DO IT JUST THINK ]
|
|
// +----------------------------------------------------------------------
|
|
// | Copyright (c) 2026-2036 http://ywxapp.cn All rights reserved.
|
|
// +----------------------------------------------------------------------
|
|
// | Author: ywxapp<admin@ywxapp.cn>
|
|
// +----------------------------------------------------------------------
|
|
declare (strict_types = 1);
|
|
namespace addon\wxchat\controller\api;
|
|
|
|
use addon\wxchat\model\WxchatMessage;
|
|
use addon\wxchat\model\WxchatUnreadCount;
|
|
use think\facade\Db;
|
|
use think\facade\Request;
|
|
use ywxapp\controller\FrontendBase;
|
|
use ywxapp\model\MemberUser as UserModel;
|
|
use ywxapp\model\MemberProfile as ProfileModel;
|
|
|
|
/**
|
|
* Message 类
|
|
*
|
|
* @author ywxapp <admin@ywxapp.cn>
|
|
*/
|
|
class Message extends FrontendBase
|
|
{
|
|
protected $noNeedLogin = [];
|
|
protected $noNeedVerify = ['*'];
|
|
|
|
|
|
protected function initialize()
|
|
{}
|
|
|
|
/**
|
|
* 发送消息(HTTP 落库,WebSocket 实时推送由 worker 处理)
|
|
*/
|
|
public function send()
|
|
{
|
|
$uid = $this->auth->model->uid;
|
|
$receiverId = (int) Request::post('receiver_id', 0);
|
|
$receiverType = (int) Request::post('receiver_type', 0); // 0-单聊 1-群聊
|
|
$content = trim((string) Request::post('content', ''));
|
|
$contentType = (int) Request::post('content_type', 0);
|
|
|
|
if (! $receiverId || $receiverId == $uid) {
|
|
$this->error('接收者无效');
|
|
}
|
|
if ($content === '' && $contentType == 0) {
|
|
$this->error('消息内容不能为空');
|
|
}
|
|
|
|
$msg = new WxchatMessage();
|
|
$msg->sender_id = $uid;
|
|
$msg->receiver_type = $receiverType;
|
|
$msg->receiver_id = $receiverId;
|
|
$msg->content = $content;
|
|
$msg->content_type = $contentType;
|
|
$msg->save();
|
|
|
|
// 更新对方未读计数(单聊)
|
|
if ($receiverType == 0) {
|
|
WxchatUnreadCount::increment($receiverId, 0, $uid);
|
|
}
|
|
|
|
$this->success($msg->toArray(), '发送成功');
|
|
}
|
|
|
|
/**
|
|
* 会话历史(单聊 / 群聊)
|
|
*/
|
|
public function history()
|
|
{
|
|
$uid = $this->auth->uid;
|
|
$contactId = (int) Request::get('contact_id', 0);
|
|
$contactType = (int) Request::get('contact_type', 0);
|
|
$limit = (int) Request::get('limit', 20);
|
|
$page = (int) Request::get('page', 1);
|
|
|
|
if (! $contactId) {
|
|
$this->error('会话对象无效');
|
|
}
|
|
|
|
$query = WxchatMessage::where('is_recalled', 0)
|
|
->where('receiver_type', $contactType);
|
|
if ($contactType == 0) {
|
|
// 单聊:取双方互发消息(修复原逻辑因外层 receiver_id 过滤而漏掉对方发来的消息)
|
|
$query->where(function ($q) use ($uid, $contactId) {
|
|
$q->where(function ($q) use ($uid, $contactId) {
|
|
$q->where('sender_id', $uid)->where('receiver_id', $contactId);
|
|
})->whereOr(function ($q) use ($uid, $contactId) {
|
|
$q->where('sender_id', $contactId)->where('receiver_id', $uid);
|
|
});
|
|
});
|
|
} else {
|
|
$query->where('receiver_id', $contactId);
|
|
}
|
|
$list = $query->order('create_at', 'desc')
|
|
->paginate($limit, false, ['page' => $page]);
|
|
|
|
// 单聊:读取后清零未读
|
|
if ($contactType == 0) {
|
|
WxchatUnreadCount::reset($uid, 0, $contactId);
|
|
}
|
|
|
|
$this->success([
|
|
'list' => $list->items(),
|
|
'total' => $list->total(),
|
|
'pages' => $list->lastPage(),
|
|
]);
|
|
}
|
|
|
|
/**
|
|
* 未读消息列表
|
|
*/
|
|
public function unread()
|
|
{
|
|
$uid = $this->auth->model->uid;
|
|
$list = WxchatUnreadCount::where('user_id', $uid)
|
|
->where('unread_count', '>', 0)
|
|
->order('update_at', 'desc')
|
|
->select();
|
|
$this->success($list);
|
|
}
|
|
|
|
/**
|
|
* 会话列表(聚合单聊最新一条消息 + 未读 + 对方资料/在线状态)
|
|
*/
|
|
public function conversations()
|
|
{
|
|
$uid = $this->auth->model->uid;
|
|
|
|
$msgs = WxchatMessage::where('receiver_type', 0)
|
|
->where('is_recalled', 0)
|
|
->where(function ($q) use ($uid) {
|
|
$q->where('sender_id', $uid)->whereOr('receiver_id', $uid);
|
|
})
|
|
->order('id', 'desc')
|
|
->limit(1000)
|
|
->select();
|
|
|
|
$convMap = [];
|
|
$peerIds = [];
|
|
foreach ($msgs as $m) {
|
|
$sid = (int) $m->sender_id;
|
|
$rid = (int) $m->receiver_id;
|
|
$peer = ($sid == $uid) ? $rid : $sid;
|
|
if (! isset($convMap[$peer])) {
|
|
$convMap[$peer] = [
|
|
'peer_id' => $peer,
|
|
'last_content' => $m->content,
|
|
'last_content_type' => (int) $m->content_type,
|
|
'last_time' => (int) $m->create_at,
|
|
'last_sender_id' => $sid,
|
|
];
|
|
$peerIds[] = $peer;
|
|
}
|
|
}
|
|
|
|
if (empty($peerIds)) {
|
|
$this->success(['list' => [], 'total' => 0]);
|
|
return;
|
|
}
|
|
|
|
$users = UserModel::where('uid', 'in', $peerIds)->column('*', 'uid');
|
|
$unread = WxchatUnreadCount::where('user_id', $uid)
|
|
->where('contact_type', 0)
|
|
->where('contact_id', 'in', $peerIds)
|
|
->column('unread_count', 'contact_id');
|
|
$onlineMap = MemberProfile::where('uid', 'in', $peerIds)->column('online_status', 'uid');
|
|
|
|
$list = [];
|
|
foreach ($convMap as $peer => $c) {
|
|
$u = $users[$peer] ?? [];
|
|
$list[] = [
|
|
'peer_id' => $peer,
|
|
'nickname' => $u['nickname'] ?? '',
|
|
'avatar' => $u['avatar'] ?? '',
|
|
'online' => ((int) ($onlineMap[$peer] ?? 0)) == 1,
|
|
'last_content' => $c['last_content'],
|
|
'last_content_type' => $c['last_content_type'],
|
|
'last_time' => $c['last_time'],
|
|
'unread_count' => (int) ($unread[$peer] ?? 0),
|
|
'is_self' => $c['last_sender_id'] == $uid,
|
|
];
|
|
}
|
|
|
|
usort($list, function ($a, $b) {
|
|
return $b['last_time'] - $a['last_time'];
|
|
});
|
|
|
|
$this->success(['list' => $list, 'total' => count($list)]);
|
|
}
|
|
|
|
/**
|
|
* 撤回消息
|
|
*/
|
|
public function recall()
|
|
{
|
|
$userId = $this->auth->model->uid;
|
|
$messageId = (int) Request::post('message_id', 0);
|
|
|
|
$message = WxchatMessage::find($messageId);
|
|
if (! $message || $message->sender_id != $userId) {
|
|
$this->error('无权撤回', 403);
|
|
}
|
|
|
|
$message->is_recalled = 1;
|
|
$message->recalled_at = date('Y-m-d H:i:s');
|
|
$message->save();
|
|
|
|
$this->success([], '撤回成功');
|
|
}
|
|
}
|