162 lines
5.1 KiB
PHP
162 lines
5.1 KiB
PHP
|
|
<?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 = 10;
|
|||
|
|
|
|||
|
|
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', '>', 34426)
|
|||
|
|
->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];
|
|||
|
|
}
|
|||
|
|
}
|