Files
cunkebao_v3/Server/application/common/service/FriendTransferService.php
2026-01-13 10:20:33 +08:00

255 lines
10 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\common\service;
use app\api\controller\AutomaticAssign;
use app\api\controller\AccountController;
use think\Db;
use think\facade\Log;
/**
* 好友迁移服务类
* 负责处理好友在不同账号之间的迁移逻辑
*/
class FriendTransferService
{
/**
* 迁移好友到其他账号
* @param int $wechatFriendId 微信好友ID
* @param int $currentAccountId 当前账号ID
* @param string $reason 迁移原因
* @return array ['success' => bool, 'message' => string, 'toAccountId' => int|null]
*/
public function transferFriend($wechatFriendId, $currentAccountId, $reason = '')
{
try {
// 获取好友信息
$friend = Db::table('s2_wechat_friend')->where('id', $wechatFriendId)->find();
if (empty($friend)) {
return [
'success' => false,
'message' => '好友不存在',
'toAccountId' => null
];
}
// 获取当前账号的部门信息
$accountData = Db::table('s2_company_account')->where('id', $currentAccountId)->find();
if (empty($accountData)) {
return [
'success' => false,
'message' => '当前账号不存在',
'toAccountId' => null
];
}
// 获取同部门的在线账号列表
$accountController = new AccountController();
$accountController->getlist([
'pageIndex' => 0,
'pageSize' => 100,
'departmentId' => $accountData['departmentId']
]);
$accountIds = Db::table('s2_company_account')
->where([
'departmentId' => $accountData['departmentId'],
'alive' => 1
])
->column('id');
if (empty($accountIds)) {
return [
'success' => false,
'message' => '没有可用的在线账号',
'toAccountId' => null
];
}
// 如果好友当前账号不在可用账号列表中,或者需要迁移到其他账号
$needTransfer = !in_array($friend['accountId'], $accountIds);
// 如果需要迁移,选择目标账号
if ($needTransfer || $currentAccountId != $friend['accountId']) {
// 排除当前账号,选择其他账号
$availableAccountIds = array_filter($accountIds, function($id) use ($currentAccountId) {
return $id != $currentAccountId;
});
if (empty($availableAccountIds)) {
return [
'success' => false,
'message' => '没有其他可用的在线账号',
'toAccountId' => null
];
}
// 随机选择一个账号
$availableAccountIds = array_values($availableAccountIds);
$randomKey = array_rand($availableAccountIds, 1);
$toAccountId = $availableAccountIds[$randomKey];
// 获取目标账号信息
$toAccountData = Db::table('s2_company_account')->where('id', $toAccountId)->find();
if (empty($toAccountData)) {
return [
'success' => false,
'message' => '目标账号不存在',
'toAccountId' => null
];
}
// 执行迁移
$automaticAssign = new AutomaticAssign();
$result = $automaticAssign->allotWechatFriend([
'wechatFriendId' => $wechatFriendId,
'toAccountId' => $toAccountId
], true);
$resultData = json_decode($result, true);
if (isset($resultData['code']) && $resultData['code'] == 200) {
// 更新好友的账号信息
Db::table('s2_wechat_friend')
->where('id', $wechatFriendId)
->update([
'accountId' => $toAccountId,
'accountUserName' => $toAccountData['userName'],
'accountRealName' => $toAccountData['realName'],
'accountNickname' => $toAccountData['nickname'],
]);
$logMessage = "好友迁移成功好友ID={$wechatFriendId},从账号{$currentAccountId}迁移到账号{$toAccountId}";
if (!empty($reason)) {
$logMessage .= ",原因:{$reason}";
}
Log::info($logMessage);
return [
'success' => true,
'message' => '好友迁移成功',
'toAccountId' => $toAccountId
];
} else {
$errorMsg = isset($resultData['msg']) ? $resultData['msg'] : '迁移失败';
Log::error("好友迁移失败好友ID={$wechatFriendId},错误:{$errorMsg}");
return [
'success' => false,
'message' => $errorMsg,
'toAccountId' => null
];
}
}
return [
'success' => true,
'message' => '好友已在正确的账号上,无需迁移',
'toAccountId' => $friend['accountId']
];
} catch (\Exception $e) {
Log::error("好友迁移异常好友ID={$wechatFriendId},错误:" . $e->getMessage());
return [
'success' => false,
'message' => '迁移异常:' . $e->getMessage(),
'toAccountId' => null
];
}
}
/**
* 检查并迁移未读或未回复的好友
* @param int $unreadMinutes 未读分钟数默认30分钟
* @return array ['total' => int, 'transferred' => int, 'failed' => int]
*/
public function checkAndTransferUnreadOrUnrepliedFriends($unreadMinutes = 30)
{
$total = 0;
$transferred = 0;
$failed = 0;
try {
$timeThreshold = time() - ($unreadMinutes * 60);
// 查询需要迁移的好友
// 条件最后一条消息是用户发送的消息isSend=0且超过指定分钟数且客服在这之后没有回复
// 即用户发送了消息但客服超过30分钟没有回复需要迁移给其他客服处理
// 使用子查询找到每个好友的最后一条消息
// SQL逻辑说明
// 1. 找到每个好友的最后一条消息通过MAX(id)
// 2. 最后一条消息必须是用户发送的isSend=0即客服接收的消息
// 3. 这条消息的时间超过30分钟前wm.wechatTime <= timeThreshold
// 4. 在这条用户消息之后客服没有发送任何回复NOT EXISTS isSend=1的消息
// 5. 满足以上条件的好友说明客服超过30分钟未回复需要迁移给其他客服
$sql = "
SELECT DISTINCT
wf.id as friendId,
wf.accountId,
wm.wechatAccountId,
wm.wechatTime,
wm.id as lastMessageId
FROM s2_wechat_friend wf
INNER JOIN (
SELECT wechatFriendId, MAX(id) as maxId
FROM s2_wechat_message
WHERE type = 1
GROUP BY wechatFriendId
) last_msg ON wf.id = last_msg.wechatFriendId
INNER JOIN s2_wechat_message wm ON wm.id = last_msg.maxId
WHERE wf.isDeleted = 0
AND wm.type = 1
AND wm.isSend = 0 -- 最后一条消息是用户发送的(客服接收的)
AND wm.wechatTime <= ? -- 超过指定时间默认30分钟
AND NOT EXISTS (
-- 检查在这条用户消息之后,是否有客服的回复
SELECT 1
FROM s2_wechat_message
WHERE wechatFriendId = wf.id
AND type = 1
AND isSend = 1 -- 客服发送的消息
AND wechatTime > wm.wechatTime -- 在用户消息之后
)
AND wf.accountId IS NOT NULL
";
$friends = Db::query($sql, [$timeThreshold]);
$total = count($friends);
Log::info("开始检查未读/未回复好友,共找到 {$total} 个需要迁移的好友");
foreach ($friends as $friend) {
$result = $this->transferFriend(
$friend['friendId'],
$friend['accountId'],
"消息未读或未回复超过{$unreadMinutes}分钟"
);
if ($result['success']) {
$transferred++;
} else {
$failed++;
Log::warning("好友迁移失败好友ID={$friend['friendId']},原因:{$result['message']}");
}
}
Log::info("未读/未回复好友迁移完成:总计{$total},成功{$transferred},失败{$failed}");
return [
'total' => $total,
'transferred' => $transferred,
'failed' => $failed
];
} catch (\Exception $e) {
Log::error("检查未读/未回复好友异常:" . $e->getMessage());
return [
'total' => $total,
'transferred' => $transferred,
'failed' => $failed
];
}
}
}