修复随机号码前先按权重随机工单,并修复降权号码筛选与清理
This commit is contained in:
@@ -0,0 +1,184 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace app\common\service;
|
||||
|
||||
use app\admin\model\split\Number;
|
||||
use think\Db;
|
||||
|
||||
/**
|
||||
* 下号比率触线降权(ratio_deferred)规则与降权池清理
|
||||
*
|
||||
* 降权前提:已有落地页访问(visit_count > last_sync_visit_count),
|
||||
* 且自上次同步以来进线未增长时累计 streak,触线才标记降权。
|
||||
*/
|
||||
class SplitNumberRatioDeferredService
|
||||
{
|
||||
/**
|
||||
* 是否具备计入 streak 的落地页访问基数
|
||||
*
|
||||
* @param array<string, mixed>|Number $number
|
||||
*/
|
||||
public function hasLandingVisitBaseline($number): bool
|
||||
{
|
||||
$visitCount = $this->readInt($number, 'visit_count');
|
||||
if ($visitCount <= 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$lastVisit = $this->readInt($number, 'last_sync_visit_count');
|
||||
|
||||
return $visitCount > $lastVisit;
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据访问与进线快照计算新的 streak
|
||||
*
|
||||
* @param array<string, mixed>|Number $number
|
||||
*/
|
||||
public function computeStreakForVisit($number, int $currentStreak): int
|
||||
{
|
||||
if (!$this->hasLandingVisitBaseline($number)) {
|
||||
return $currentStreak;
|
||||
}
|
||||
|
||||
$inboundCount = $this->readInt($number, 'inbound_count');
|
||||
$lastInbound = $this->readInt($number, 'last_sync_inbound_count');
|
||||
|
||||
if ($inboundCount <= $lastInbound) {
|
||||
return $currentStreak + 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* 同步侧:根据 visit / inbound 与上次同步检查点重算 streak
|
||||
*
|
||||
* @param array<string, mixed>|Number $number
|
||||
*/
|
||||
public function computeStreakForSync($number, int $currentStreak): int
|
||||
{
|
||||
$visitCount = $this->readInt($number, 'visit_count');
|
||||
if ($visitCount <= 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
$lastVisit = $this->readInt($number, 'last_sync_visit_count');
|
||||
$inboundCount = $this->readInt($number, 'inbound_count');
|
||||
$lastInbound = $this->readInt($number, 'last_sync_inbound_count');
|
||||
|
||||
if ($inboundCount > $lastInbound) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ($visitCount > $lastVisit) {
|
||||
return $currentStreak + ($visitCount - $lastVisit);
|
||||
}
|
||||
|
||||
return $currentStreak;
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否应标记 ratio_deferred(访问侧触线降权,不关 status)
|
||||
*/
|
||||
public function shouldMarkDeferred(int $streak, int $assignRatio, bool $hasLandingBaseline): bool
|
||||
{
|
||||
return $hasLandingBaseline && $assignRatio > 0 && $streak >= $assignRatio;
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否为应清理的无效降权记录
|
||||
*
|
||||
* @param array<string, mixed>|Number $number
|
||||
*/
|
||||
public function isInvalidDeferredRecord($number): bool
|
||||
{
|
||||
if ($this->readInt($number, 'ratio_deferred') !== 1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return !$this->hasLandingVisitBaseline($number);
|
||||
}
|
||||
|
||||
/**
|
||||
* 清理无效降权标记(ratio_deferred=1 但无有效落地页访问基线)
|
||||
*
|
||||
* @param int[]|null $adminIds 数据权限管理员 ID 列表,null 表示不限制
|
||||
* @return int 清理条数
|
||||
*/
|
||||
public function cleanupInvalidDeferred(?array $adminIds = null): int
|
||||
{
|
||||
$query = Number::where('ratio_deferred', 1);
|
||||
if ($adminIds !== null && $adminIds !== []) {
|
||||
$query->where('admin_id', 'in', $adminIds);
|
||||
}
|
||||
|
||||
$rows = $query->field('id,visit_count,last_sync_visit_count,ratio_deferred,no_inbound_click_streak')->select();
|
||||
if ($rows === null || $rows === []) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
$now = time();
|
||||
$count = 0;
|
||||
Db::startTrans();
|
||||
try {
|
||||
foreach ($rows as $row) {
|
||||
if (!$this->isInvalidDeferredRecord($row)) {
|
||||
continue;
|
||||
}
|
||||
$update = [
|
||||
'ratio_deferred' => 0,
|
||||
'ratio_deferred_at' => null,
|
||||
'updatetime' => $now,
|
||||
];
|
||||
if ($this->readInt($row, 'visit_count') <= 0) {
|
||||
$update['no_inbound_click_streak'] = 0;
|
||||
}
|
||||
Number::where('id', (int) $row['id'])->update($update);
|
||||
$count++;
|
||||
}
|
||||
Db::commit();
|
||||
} catch (\Throwable $e) {
|
||||
Db::rollback();
|
||||
throw $e;
|
||||
}
|
||||
|
||||
return $count;
|
||||
}
|
||||
|
||||
/**
|
||||
* 统计当前权限范围内无效降权条数(清理前预览)
|
||||
*
|
||||
* @param int[]|null $adminIds
|
||||
*/
|
||||
public function countInvalidDeferred(?array $adminIds = null): int
|
||||
{
|
||||
$query = Number::where('ratio_deferred', 1);
|
||||
if ($adminIds !== null && $adminIds !== []) {
|
||||
$query->where('admin_id', 'in', $adminIds);
|
||||
}
|
||||
|
||||
$total = 0;
|
||||
foreach ($query->field('id,visit_count,last_sync_visit_count,ratio_deferred')->select() as $row) {
|
||||
if ($this->isInvalidDeferredRecord($row)) {
|
||||
$total++;
|
||||
}
|
||||
}
|
||||
|
||||
return $total;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, mixed>|Number $number
|
||||
*/
|
||||
private function readInt($number, string $field): int
|
||||
{
|
||||
if (is_array($number)) {
|
||||
return (int) ($number[$field] ?? 0);
|
||||
}
|
||||
|
||||
return (int) $number->getAttr($field);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user