264 lines
9.2 KiB
PHP
264 lines
9.2 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\worker\handle;
|
|
|
|
use addon\wxchat\model\WxchatFriend;
|
|
use addon\wxchat\model\WxchatGroup;
|
|
use addon\wxchat\model\WxchatGroupMember;
|
|
use addon\wxchat\worker\enum\MsgFrame;
|
|
use addon\wxchat\worker\enum\MsgType;
|
|
use addon\wxchat\worker\MsgReply;
|
|
use GatewayWorker\Lib\Gateway;
|
|
use ywxapp\model\MemberUser;
|
|
|
|
/**
|
|
* 关系消息处理(加好友 / 同意 / 拒绝 / 加群 / 邀请)
|
|
* 真实落库:wxapp_wxchat_friend / wxapp_wxchat_group_members / wxapp_wxchat_groups
|
|
*
|
|
* 协议约定(客户端上行):
|
|
* {
|
|
* "header": { "type":"rel", "timestamp":... },
|
|
* "payload": { "type":"friend_request"|"friend_agree"|"friend_refuse"|"group_join"|"group_invite",
|
|
* "receiver":<对方UID>, "session_id":<群ID>, "remark":"备注/招呼语" }
|
|
* }
|
|
*/
|
|
class RelationHandle
|
|
{
|
|
|
|
public static function handle($client_id, $header, $payload)
|
|
{
|
|
$uid = Gateway::getUidByClientId($client_id);
|
|
if (empty($uid)) {
|
|
MsgReply::sendError($client_id, '未认证,请先登录');
|
|
return;
|
|
}
|
|
|
|
// 关系子类型:优先 payload.type(与 ChatHandle 一致),兼容 header.type
|
|
$subType = (string) ($payload->type ?? ($header->type ?? ''));
|
|
$peer = (int) ($payload->receiver ?? 0);
|
|
$groupId = (int) ($payload->session_id ?? ($payload->group_id ?? 0));
|
|
$remark = trim((string) ($payload->remark ?? ($payload->content ?? '')));
|
|
|
|
switch ($subType) {
|
|
case MsgType::FRIEND_REQUEST->value:
|
|
self::friendRequest($client_id, $uid, $peer, $remark);
|
|
break;
|
|
case MsgType::FRIEND_AGREE->value:
|
|
self::friendAgree($client_id, $uid, $peer);
|
|
break;
|
|
case MsgType::FRIEND_REFUSE->value:
|
|
self::friendRefuse($client_id, $uid, $peer);
|
|
break;
|
|
case MsgType::GROUP_JOIN->value:
|
|
self::groupJoin($client_id, $uid, $groupId);
|
|
break;
|
|
case MsgType::GROUP_INVITE->value:
|
|
self::groupInvite($client_id, $uid, $groupId, $peer);
|
|
break;
|
|
default:
|
|
MsgReply::sendError($client_id, '不支持的关系消息类型: ' . $subType);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 好友申请:写入待处理好友记录(status=0),并实时通知对方
|
|
*/
|
|
private static function friendRequest($client_id, $uid, $peer, $remark)
|
|
{
|
|
if (! $peer) {
|
|
MsgReply::sendError($client_id, '对方 UID 无效');
|
|
return;
|
|
}
|
|
if ($peer == $uid) {
|
|
MsgReply::sendError($client_id, '不能添加自己为好友');
|
|
return;
|
|
}
|
|
// 已是好友(双向任一存在 status=1)
|
|
if (self::isFriend($uid, $peer)) {
|
|
MsgReply::sendError($client_id, '你们已是好友');
|
|
return;
|
|
}
|
|
// 去重:已存在待处理请求则不重复写入
|
|
$exist = WxchatFriend::where('uid', $uid)->where('fid', $peer)->where('status', 0)->find();
|
|
if (! $exist) {
|
|
$fr = new WxchatFriend();
|
|
$fr->uid = $uid;
|
|
$fr->fid = $peer;
|
|
$fr->remark = $remark;
|
|
$fr->status = 0; // 0-请求中
|
|
$fr->create_at = time();
|
|
$fr->save();
|
|
}
|
|
|
|
$myName = self::nickname($uid);
|
|
// 实时通知对方
|
|
MsgReply::sendToUid($peer, MsgFrame::RELATION->value, MsgType::FRIEND_REQUEST->value, '收到好友申请', [
|
|
'from' => $uid,
|
|
'from_name' => $myName,
|
|
'remark' => $remark,
|
|
]);
|
|
// 回执发送方
|
|
MsgReply::send($client_id, MsgFrame::RELATION->value, MsgType::FRIEND_REQUEST->value, '已发送好友申请', [
|
|
'to' => $peer,
|
|
]);
|
|
}
|
|
|
|
/**
|
|
* 同意申请:$uid 同意 $peer 发来的请求,建立双向好友
|
|
*/
|
|
private static function friendAgree($client_id, $uid, $peer)
|
|
{
|
|
if (! $peer) {
|
|
MsgReply::sendError($client_id, '对方 UID 无效');
|
|
return;
|
|
}
|
|
$req = WxchatFriend::where('uid', $peer)->where('fid', $uid)->where('status', 0)->find();
|
|
if (! $req) {
|
|
MsgReply::sendError($client_id, '无待处理的好友申请');
|
|
return;
|
|
}
|
|
$req->status = 1; // 1-已通过
|
|
$req->update_at = time();
|
|
$req->save();
|
|
|
|
// 写入反向好友记录(保证双向查询一致)
|
|
if (! self::isFriend($uid, $peer)) {
|
|
$reverse = new WxchatFriend();
|
|
$reverse->uid = $uid;
|
|
$reverse->fid = $peer;
|
|
$reverse->status = 1;
|
|
$reverse->create_at = time();
|
|
$reverse->save();
|
|
}
|
|
|
|
// 通知申请方
|
|
MsgReply::sendToUid($peer, MsgFrame::RELATION->value, MsgType::FRIEND_AGREE->value, '对方已通过你的好友申请', [
|
|
'from' => $uid,
|
|
'from_name' => self::nickname($uid),
|
|
]);
|
|
MsgReply::send($client_id, MsgFrame::RELATION->value, MsgType::FRIEND_AGREE->value, '已同意', [
|
|
'to' => $peer,
|
|
]);
|
|
}
|
|
|
|
/**
|
|
* 拒绝申请
|
|
*/
|
|
private static function friendRefuse($client_id, $uid, $peer)
|
|
{
|
|
if (! $peer) {
|
|
MsgReply::sendError($client_id, '对方 UID 无效');
|
|
return;
|
|
}
|
|
$req = WxchatFriend::where('uid', $peer)->where('fid', $uid)->where('status', 0)->find();
|
|
if (! $req) {
|
|
MsgReply::sendError($client_id, '无待处理的好友申请');
|
|
return;
|
|
}
|
|
$req->status = 2; // 2-已拒绝
|
|
$req->update_at = time();
|
|
$req->save();
|
|
|
|
MsgReply::sendToUid($peer, MsgFrame::RELATION->value, MsgType::FRIEND_REFUSE->value, '对方拒绝了你的好友申请', [
|
|
'from' => $uid,
|
|
]);
|
|
MsgReply::send($client_id, MsgFrame::RELATION->value, MsgType::FRIEND_REFUSE->value, '已拒绝', [
|
|
'to' => $peer,
|
|
]);
|
|
}
|
|
|
|
/**
|
|
* 主动加群:加入 group_members
|
|
*/
|
|
private static function groupJoin($client_id, $uid, $groupId)
|
|
{
|
|
if (! $groupId) {
|
|
MsgReply::sendError($client_id, '群组 ID 无效');
|
|
return;
|
|
}
|
|
$group = WxchatGroup::find($groupId);
|
|
if (! $group) {
|
|
MsgReply::sendError($client_id, '群组不存在');
|
|
return;
|
|
}
|
|
if (WxchatGroupMember::where('gid', $groupId)->where('uid', $uid)->find()) {
|
|
MsgReply::sendError($client_id, '你已在群内');
|
|
return;
|
|
}
|
|
self::addGroupMember($groupId, $uid, 0);
|
|
MsgReply::send($client_id, MsgFrame::RELATION->value, MsgType::GROUP_JOIN->value, '已加入群组', [
|
|
'group_id' => $groupId,
|
|
]);
|
|
}
|
|
|
|
/**
|
|
* 邀请加群:$uid 邀请 $peer 加入群组
|
|
*/
|
|
private static function groupInvite($client_id, $uid, $groupId, $peer)
|
|
{
|
|
if (! $groupId || ! $peer) {
|
|
MsgReply::sendError($client_id, '群组或受邀人无效');
|
|
return;
|
|
}
|
|
$group = WxchatGroup::find($groupId);
|
|
if (! $group) {
|
|
MsgReply::sendError($client_id, '群组不存在');
|
|
return;
|
|
}
|
|
if (! WxchatGroupMember::where('gid', $groupId)->where('uid', $peer)->find()) {
|
|
self::addGroupMember($groupId, $peer, 0);
|
|
}
|
|
MsgReply::sendToUid($peer, MsgFrame::RELATION->value, MsgType::GROUP_INVITE->value, '你被邀请加入群组', [
|
|
'group_id' => $groupId,
|
|
'from' => $uid,
|
|
'from_name' => self::nickname($uid),
|
|
]);
|
|
MsgReply::send($client_id, MsgFrame::RELATION->value, MsgType::GROUP_INVITE->value, '邀请已发送', [
|
|
'group_id' => $groupId,
|
|
'to' => $peer,
|
|
]);
|
|
}
|
|
|
|
/**
|
|
* 写入群成员并自增群人数
|
|
*/
|
|
private static function addGroupMember($groupId, $uid, $role)
|
|
{
|
|
$m = new WxchatGroupMember();
|
|
$m->gid = $groupId;
|
|
$m->uid = $uid;
|
|
$m->role = $role;
|
|
$m->join_time = date('Y-m-d H:i:s');
|
|
$m->save();
|
|
WxchatGroup::where('id', $groupId)->inc('member_count')->update();
|
|
}
|
|
|
|
|
|
private static function isFriend($uid, $fid): bool
|
|
{
|
|
return (bool) WxchatFriend::where('uid', $uid)
|
|
->where('fid', $fid)
|
|
->where('status', 1)
|
|
->find();
|
|
}
|
|
|
|
|
|
private static function nickname($uid): string
|
|
{
|
|
try {
|
|
$name = MemberUser::where('uid', $uid)->value('nickname');
|
|
return $name ?: '';
|
|
} catch (\Throwable $e) {
|
|
return '';
|
|
}
|
|
}
|
|
}
|