255 lines
10 KiB
PHP
255 lines
10 KiB
PHP
<?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
|
||
];
|
||
}
|
||
}
|
||
}
|
||
|