2026-06-09 03:36:30 +08:00
|
|
|
|
<?php
|
|
|
|
|
|
|
|
|
|
|
|
declare(strict_types=1);
|
|
|
|
|
|
|
|
|
|
|
|
namespace app\common\service;
|
|
|
|
|
|
|
|
|
|
|
|
use app\admin\model\split\Link;
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
2026-07-01 01:26:27 +08:00
|
|
|
|
* 分流链接随机打乱配置与落地页选号
|
|
|
|
|
|
*
|
|
|
|
|
|
* - random_shuffle=0:跨工单合并号码池,按 id 顺序严格轮转
|
|
|
|
|
|
* - random_shuffle=1:跨工单合并号码池,每次访问完全随机选号
|
|
|
|
|
|
* - 同步写入时 random_shuffle=1 还会打乱新号码 insert 顺序(影响 id 分布)
|
2026-06-09 03:36:30 +08:00
|
|
|
|
*/
|
|
|
|
|
|
class SplitNumberWeighService
|
|
|
|
|
|
{
|
|
|
|
|
|
/**
|
2026-07-01 01:26:27 +08:00
|
|
|
|
* 链接是否开启随机打乱
|
2026-06-09 03:36:30 +08:00
|
|
|
|
*/
|
|
|
|
|
|
public static function isRandomShuffleEnabled(int $linkId): bool
|
|
|
|
|
|
{
|
|
|
|
|
|
if ($linkId <= 0) {
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
return (int) Link::where('id', $linkId)->value('random_shuffle') === 1;
|
|
|
|
|
|
}
|
2026-07-01 01:26:27 +08:00
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 解析本次访问应使用的号码下标(0 .. numberCount-1)
|
|
|
|
|
|
*
|
|
|
|
|
|
* @param int $linkId 分流链接 ID
|
|
|
|
|
|
* @param int $numberCount 可用号码数量
|
|
|
|
|
|
* @param SplitRoundRobinStore $roundRobinStore 关闭随机打乱时的轮转计数器
|
2026-07-04 11:46:00 +08:00
|
|
|
|
* @param string $poolKey 选号池标识(preferred / deferred 等)
|
2026-07-01 01:26:27 +08:00
|
|
|
|
*/
|
|
|
|
|
|
public static function resolvePickIndex(
|
|
|
|
|
|
int $linkId,
|
|
|
|
|
|
int $numberCount,
|
2026-07-04 11:46:00 +08:00
|
|
|
|
SplitRoundRobinStore $roundRobinStore,
|
|
|
|
|
|
string $poolKey = 'main'
|
2026-07-01 01:26:27 +08:00
|
|
|
|
): int {
|
|
|
|
|
|
if ($numberCount <= 0) {
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
}
|
|
|
|
|
|
if ($numberCount === 1) {
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (self::isRandomShuffleEnabled($linkId)) {
|
|
|
|
|
|
return random_int(0, $numberCount - 1);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-07-04 11:46:00 +08:00
|
|
|
|
return $roundRobinStore->nextIndex($linkId, $numberCount, $poolKey);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 从号码行列表中按链接配置选一条(严格轮转或随机)
|
|
|
|
|
|
*
|
|
|
|
|
|
* @param array<int, array<string, mixed>|Number> $rows
|
|
|
|
|
|
* @return array<string, mixed>|Number|null
|
|
|
|
|
|
*/
|
|
|
|
|
|
public static function pickRowFromList(
|
|
|
|
|
|
int $linkId,
|
|
|
|
|
|
array $rows,
|
|
|
|
|
|
SplitRoundRobinStore $roundRobinStore,
|
|
|
|
|
|
string $poolKey = 'main'
|
|
|
|
|
|
) {
|
|
|
|
|
|
$count = count($rows);
|
|
|
|
|
|
if ($count === 0) {
|
|
|
|
|
|
return null;
|
|
|
|
|
|
}
|
|
|
|
|
|
$index = self::resolvePickIndex($linkId, $count, $roundRobinStore, $poolKey);
|
|
|
|
|
|
return $rows[$index] ?? $rows[0];
|
2026-07-01 01:26:27 +08:00
|
|
|
|
}
|
2026-06-09 03:36:30 +08:00
|
|
|
|
}
|