修复A2C工单蜘蛛
This commit is contained in:
@@ -7,12 +7,16 @@ namespace app\common\service;
|
||||
use app\admin\model\split\Link;
|
||||
|
||||
/**
|
||||
* 分流链接随机打乱配置读取
|
||||
* 分流链接随机打乱配置与落地页选号
|
||||
*
|
||||
* - random_shuffle=0:跨工单合并号码池,按 id 顺序严格轮转
|
||||
* - random_shuffle=1:跨工单合并号码池,每次访问完全随机选号
|
||||
* - 同步写入时 random_shuffle=1 还会打乱新号码 insert 顺序(影响 id 分布)
|
||||
*/
|
||||
class SplitNumberWeighService
|
||||
{
|
||||
/**
|
||||
* 链接是否开启随机打乱(新号码按随机插入顺序写入,跳转按 id 顺序轮转)
|
||||
* 链接是否开启随机打乱
|
||||
*/
|
||||
public static function isRandomShuffleEnabled(int $linkId): bool
|
||||
{
|
||||
@@ -21,4 +25,30 @@ class SplitNumberWeighService
|
||||
}
|
||||
return (int) Link::where('id', $linkId)->value('random_shuffle') === 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* 解析本次访问应使用的号码下标(0 .. numberCount-1)
|
||||
*
|
||||
* @param int $linkId 分流链接 ID
|
||||
* @param int $numberCount 可用号码数量
|
||||
* @param SplitRoundRobinStore $roundRobinStore 关闭随机打乱时的轮转计数器
|
||||
*/
|
||||
public static function resolvePickIndex(
|
||||
int $linkId,
|
||||
int $numberCount,
|
||||
SplitRoundRobinStore $roundRobinStore
|
||||
): int {
|
||||
if ($numberCount <= 0) {
|
||||
return 0;
|
||||
}
|
||||
if ($numberCount === 1) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (self::isRandomShuffleEnabled($linkId)) {
|
||||
return random_int(0, $numberCount - 1);
|
||||
}
|
||||
|
||||
return $roundRobinStore->nextIndex($linkId, $numberCount);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,7 +9,10 @@ use app\admin\model\split\Number;
|
||||
use think\Collection;
|
||||
|
||||
/**
|
||||
* 分流链接落地页:查链、轮转选号、拼接跳转 URL、访问计数
|
||||
* 分流链接落地页:查链、跨工单合并选号、拼接跳转 URL、访问计数
|
||||
*
|
||||
* 号码池为同一 split_link_id 下全部 status=normal 的号码;
|
||||
* random_shuffle 关闭时严格轮转,开启时每次访问随机选号。
|
||||
*/
|
||||
class SplitRedirectService
|
||||
{
|
||||
@@ -59,7 +62,7 @@ class SplitRedirectService
|
||||
}
|
||||
|
||||
$linkId = (int) $link->getAttr('id');
|
||||
$index = $this->roundRobinStore->nextIndex($linkId, $count);
|
||||
$index = SplitNumberWeighService::resolvePickIndex($linkId, $count, $this->roundRobinStore);
|
||||
$list = $numbers instanceof \think\Collection ? $numbers->all() : (array) $numbers;
|
||||
$picked = $list[$index] ?? $list[0] ?? null;
|
||||
if ($picked === null) {
|
||||
|
||||
@@ -11,11 +11,16 @@ use think\Db;
|
||||
|
||||
/**
|
||||
* 工单同步结果写入号码表
|
||||
*
|
||||
* 同步策略(全量镜像):
|
||||
* - 爬虫返回的号码:写入 platform_status / inbound_count,开关 status 与云控在线状态一致
|
||||
* - 爬虫未返回且 manual_manage=0:物理删除
|
||||
* - manual_manage=1:不删除,仅当仍在爬虫结果中时更新 platform_status
|
||||
*/
|
||||
class SplitTicketNumberSyncService
|
||||
{
|
||||
/**
|
||||
* 将蜘蛛返回的号码列表同步到号码管理
|
||||
* 将蜘蛛返回的号码列表同步到号码管理(全量镜像,以爬虫为准)
|
||||
*/
|
||||
public function syncFromUnifiedData(Ticket $ticket, UnifiedScrmData $data): void
|
||||
{
|
||||
@@ -61,7 +66,7 @@ class SplitTicketNumberSyncService
|
||||
$newFollowers = (int) ($row['newFollowersToday'] ?? 0);
|
||||
|
||||
if (isset($existingMap[$number])) {
|
||||
$this->updateExistingNumber($existingMap[$number], $platformStatus, $newFollowers);
|
||||
$this->updateExistingNumber($ticket, $existingMap[$number], $platformStatus, $newFollowers);
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -87,6 +92,7 @@ class SplitTicketNumberSyncService
|
||||
}
|
||||
}
|
||||
|
||||
$deleteIds = [];
|
||||
foreach ($existingMap as $number => $item) {
|
||||
if (isset($syncedNumberSet[$number])) {
|
||||
continue;
|
||||
@@ -94,18 +100,58 @@ class SplitTicketNumberSyncService
|
||||
if ((int) $item['manual_manage'] === 1) {
|
||||
continue;
|
||||
}
|
||||
Number::where('id', (int) $item['id'])->update([
|
||||
'status' => 'hidden',
|
||||
$deleteIds[] = (int) $item['id'];
|
||||
}
|
||||
if ($deleteIds !== []) {
|
||||
Number::where('id', 'in', $deleteIds)->delete();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 工单手动开启等非同步场景:按已存的 platform_status 对齐开关(不跑单号上限/下号比率)
|
||||
*/
|
||||
public function applyStatusFromPlatformSnapshot(Ticket $ticket): void
|
||||
{
|
||||
if ((string) ($ticket['status'] ?? 'hidden') !== 'normal') {
|
||||
return;
|
||||
}
|
||||
|
||||
$numbers = Number::where('admin_id', (int) $ticket['admin_id'])
|
||||
->where('split_link_id', (int) $ticket['split_link_id'])
|
||||
->where('ticket_name', (string) $ticket['ticket_name'])
|
||||
->where('manual_manage', 0)
|
||||
->select();
|
||||
|
||||
foreach ($numbers as $number) {
|
||||
$platformStatus = (string) ($number['platform_status'] ?? 'offline');
|
||||
Number::where('id', (int) $number['id'])->update([
|
||||
'status' => self::resolveSwitchStatus($ticket, $platformStatus),
|
||||
'updatetime' => time(),
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 云控在线 → 开启;离线 → 关闭;工单关闭时一律关闭
|
||||
*/
|
||||
public static function resolveSwitchStatus(Ticket $ticket, string $platformStatus): string
|
||||
{
|
||||
if ((string) ($ticket['status'] ?? 'hidden') !== 'normal') {
|
||||
return 'hidden';
|
||||
}
|
||||
|
||||
return $platformStatus === 'online' ? 'normal' : 'hidden';
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Number $row
|
||||
*/
|
||||
private function updateExistingNumber($row, string $platformStatus, int $newFollowers): void
|
||||
{
|
||||
private function updateExistingNumber(
|
||||
Ticket $ticket,
|
||||
$row,
|
||||
string $platformStatus,
|
||||
int $newFollowers
|
||||
): void {
|
||||
$update = [
|
||||
'platform_status' => $platformStatus,
|
||||
'updatetime' => time(),
|
||||
@@ -116,8 +162,8 @@ class SplitTicketNumberSyncService
|
||||
return;
|
||||
}
|
||||
|
||||
// 进线人数由同步写入,最终开关由 applyNumberRules 统一判定(单号上限/下号比率等)
|
||||
$update['inbound_count'] = max(0, $newFollowers);
|
||||
$update['status'] = self::resolveSwitchStatus($ticket, $platformStatus);
|
||||
Number::where('id', (int) $row['id'])->update($update);
|
||||
}
|
||||
|
||||
@@ -139,7 +185,7 @@ class SplitTicketNumberSyncService
|
||||
'inbound_count' => max(0, $newFollowers),
|
||||
'manual_manage' => 0,
|
||||
'platform_status' => $platformStatus,
|
||||
'status' => 'hidden',
|
||||
'status' => self::resolveSwitchStatus($ticket, $platformStatus),
|
||||
'createtime' => $now,
|
||||
'updatetime' => $now,
|
||||
];
|
||||
@@ -148,10 +194,11 @@ class SplitTicketNumberSyncService
|
||||
Db::name('split_number')->insert($data);
|
||||
} catch (\Throwable $e) {
|
||||
$exists = Number::where('split_link_id', (int) $ticket['split_link_id'])
|
||||
->where('ticket_name', (string) $ticket['ticket_name'])
|
||||
->where('number', $number)
|
||||
->find();
|
||||
if ($exists) {
|
||||
$this->updateExistingNumber($exists, $platformStatus, $newFollowers);
|
||||
$this->updateExistingNumber($ticket, $exists, $platformStatus, $newFollowers);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,7 +13,7 @@ use app\admin\model\split\Ticket;
|
||||
class SplitTicketRuleService
|
||||
{
|
||||
/**
|
||||
* 同步后应用全部规则并写回工单/号码
|
||||
* 同步后应用工单开关规则;号码开关以爬虫/platform 快照为准(不再跑单号上限/下号比率)
|
||||
*/
|
||||
public function applyAfterSync(Ticket $ticket, int $completeCount): void
|
||||
{
|
||||
@@ -22,8 +22,9 @@ class SplitTicketRuleService
|
||||
if ($fresh) {
|
||||
if ((string) $fresh['status'] === 'hidden') {
|
||||
$this->cascadeTicketClosedToNumbers($fresh);
|
||||
} else {
|
||||
(new SplitTicketNumberSyncService())->applyStatusFromPlatformSnapshot($fresh);
|
||||
}
|
||||
$this->applyNumberRules($fresh);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -69,7 +70,7 @@ class SplitTicketRuleService
|
||||
}
|
||||
|
||||
/**
|
||||
* 手动切换工单状态时,联动非手动管理的号码
|
||||
* 手动切换工单状态时,非手动号码按 platform_status 对齐开关
|
||||
*/
|
||||
public function syncNumbersWithTicketStatus(Ticket $ticket): void
|
||||
{
|
||||
@@ -78,17 +79,17 @@ class SplitTicketRuleService
|
||||
$this->cascadeTicketClosedToNumbers($ticket);
|
||||
return;
|
||||
}
|
||||
$this->applyNumberRules($ticket);
|
||||
(new SplitTicketNumberSyncService())->applyStatusFromPlatformSnapshot($ticket);
|
||||
}
|
||||
|
||||
/**
|
||||
* 工单处于开启状态时,将云控在线的非手动号码设为开启
|
||||
*
|
||||
* @deprecated 请使用 applyNumberRules(会校验单号上限/下号比率)
|
||||
* @deprecated 请使用 applyStatusFromPlatformSnapshot(以 platform_status 为准)
|
||||
*/
|
||||
public function syncOnlineNumbersWhenTicketOpen(Ticket $ticket): void
|
||||
{
|
||||
$this->applyNumberRules($ticket);
|
||||
(new SplitTicketNumberSyncService())->applyStatusFromPlatformSnapshot($ticket);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -297,7 +297,6 @@ class SplitTicketSyncService
|
||||
if ((string) $freshTicket['status'] === 'hidden') {
|
||||
$this->ruleService->cascadeTicketClosedToNumbers($freshTicket);
|
||||
}
|
||||
$this->ruleService->applyNumberRules($freshTicket);
|
||||
$ticket = $freshTicket;
|
||||
|
||||
$inboundCount = $this->numberSync->sumInboundForTicket($ticket);
|
||||
|
||||
Reference in New Issue
Block a user