, window_days: int} * ordered=排好序的 user_id 列表;counts=窗口内每人已有条数 */ public static function fairOrder(array $userIds, int $windowDays = self::DEFAULT_WINDOW_DAYS): array { $since = time() - $windowDays * 86400; $counts = []; $lastIds = []; foreach (Db::table('crm_customer') ->where('channel_id', 4) ->where('type', 2) ->whereNull('deleted_at') ->whereIn('user_id', $userIds) ->where('created_at', '>=', $since) ->groupBy('user_id') ->selectRaw('user_id, COUNT(*) AS cnt, MAX(id) AS last_id') ->get() as $r) { $uid = (int)$r->user_id; $counts[$uid] = (int)$r->cnt; $lastIds[$uid] = (int)$r->last_id; } $pos = array_flip(array_map('intval', $userIds)); $ordered = array_map('intval', $userIds); usort($ordered, function ($a, $b) use ($counts, $lastIds, $pos) { $ca = $counts[$a] ?? 0; $cb = $counts[$b] ?? 0; if ($ca !== $cb) { return $ca <=> $cb; // 窗口内分到少的优先 } $la = $lastIds[$a] ?? 0; $lb = $lastIds[$b] ?? 0; if ($la !== $lb) { return $la <=> $lb; // 最久未分到的优先 } return $pos[$a] <=> $pos[$b]; // 名单顺序(稳定) }); return ['ordered' => $ordered, 'counts' => $counts, 'window_days' => $windowDays]; } }