Files
fdesk/app/command/InquiryAssignInquiryCommand.php
T
2025-12-10 20:26:21 +08:00

162 lines
5.1 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\command;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use support\Db;
use support\Redis;
use support\exception\BusinessException;
use Webman\RedisQueue\Redis as RedisQueueRedis;
/**
* 轮询分配 inquiry_log 里的询盘给业务员,并推送到 CRM 队列
*/
class InquiryAssignInquiryCommand extends Command
{
protected static $defaultName = 'iq-assign';
protected static $defaultDescription = '轮询分配询盘给业务员,并推送到 CRM 队列';
/**
* 参与轮询的业务员 ID 列表(请按你想要的顺序填写)
* 比如:销售1=186,销售2=233...
*/
protected const SALES_USER_IDS = [
63,
64,
67,
93,
108,
132,
143,
145,
157,
160,
168,
172,
173,
191,
193,
194,
195,
196,
197
];
/**
* 轮询分配的分组 key(同一分组共用一个轮询指针)
*/
protected const ROUND_ROBIN_GROUP_KEY = 'fb_inquiry';
/**
* 每次脚本最多分配多少条
*/
protected const BATCH_LIMIT = 300;
protected function execute(InputInterface $input, OutputInterface $output): int
{
// 业务员列表检查
$userIds = array_values(array_filter(
array_map('intval', static::SALES_USER_IDS),
fn($v) => $v > 0
));
if (empty($userIds)) {
throw new BusinessException('SALES_USER_IDS 业务员列表不能为空,请先在命令中配置.');
}
// 取出“待分配”的询盘(你可以根据自己系统调整条件)
// 当前策略:status = 0 且 recipient = 0 的视为未分配
$inquiries = Db::table('inquiry_log')
->where('enter_user_id', 186)
->where('channel', 10)
->where('status', 0)
->where('recipient', 0)
->where('id', '>', 34847)
->orderBy('id')
->limit(static::BATCH_LIMIT)
->get();
if ($inquiries->isEmpty()) {
$output->writeln('<comment>没有需要分配的询盘(status=0 且 recipient=0)</comment>');
return self::SUCCESS;
}
$now = time();
$count = 0;
foreach ($inquiries as $row) {
$inquiryId = (int)$row->id;
sleep(1);
// 轮询取出一个业务员 ID
$recipientUserId = $this->nextRecipientId($userIds, static::ROUND_ROBIN_GROUP_KEY);
// 对每一条记录单独事务,避免单条异常拖垮全部
Db::transaction(function () use ($inquiryId, $recipientUserId, $now, $output, &$count) {
// 1)更新 inquiry_log
$affected = Db::table('inquiry_log')
->where('id', $inquiryId)
->update([
'recipient' => $recipientUserId,
'status' => 2,
'r_time' => $now,
't_time' => $now,
'updated_at' => $now,
]);
if ($affected === 0) {
// 被其他进程抢先更新也有可能,这里只打印提示不中断整个批次
$output->writeln("<comment>询盘 {$inquiryId} 未更新(可能已被处理)</comment>");
return;
}
// 2)构造队列 payload(后续 CRM 消费时至少知道 ID)
$res = [
'id' => $inquiryId,
'recipient' => $recipientUserId,
'dispatched_at' => $now,
'source' => 'fb_leads_inquiry',
];
// 3)推送到 CRM 队列
RedisQueueRedis::send('inquiry-to-crm-new', $res);
$count++;
$output->writeln("<info>已分配询盘 {$inquiryId} 给业务员 {$recipientUserId},并推送到队列</info>");
});
}
$output->writeln("<info>本次共分配成功 {$count} 条询盘</info>");
return self::SUCCESS;
}
/**
* 轮询获取“下一位业务员 ID”
*
* @param int[] $userIds
* @param string $groupKey
* @return int
* @throws BusinessException
*/
protected function nextRecipientId(array $userIds, string $groupKey = 'default'): int
{
$userIds = array_values(array_filter(array_map('intval', $userIds), fn($v) => $v > 0));
if (empty($userIds)) {
throw new BusinessException('轮询分配失败:业务员列表为空');
}
$count = count($userIds);
$key = 'inquiry:assign:round_robin:' . $groupKey;
// Redis INCR 是原子操作,适合并发下使用
$val = Redis::incr($key); // 第一次会从 0 变成 1
// 换算为从 0 开始的下标
$index = ($val - 1) % $count;
return $userIds[$index];
}
}