diff --git a/app/command/HesuGoogleAiInquiryImportCommand.php b/app/command/HesuGoogleAiInquiryImportCommand.php
index 8a84d45..5efa086 100644
--- a/app/command/HesuGoogleAiInquiryImportCommand.php
+++ b/app/command/HesuGoogleAiInquiryImportCommand.php
@@ -3,6 +3,7 @@
namespace app\command;
use app\common\model\CrmCustomer;
+use app\common\utils\InquiryFairAssigner;
use app\common\utils\email\InquiryDigestMail;
use app\common\utils\email\MailSend;
use app\crm\model\Country;
@@ -324,10 +325,14 @@ class HesuGoogleAiInquiryImportCommand extends Command
$output->writeln('未匹配到国家(将留空): ' . implode('、', array_keys($countryMiss)) . '');
}
- // 轮询分配(按行序 i % n)
- $n = count($targetUserIds);
+ // 公平分配:按近10天窗口内实际分到数升序(少者优先、最久未分到优先),再按序轮询
+ $fair = InquiryFairAssigner::fairOrder($targetUserIds);
+ $orderedUsers = $fair['ordered'];
+ $output->writeln('分配顺序(近' . $fair['window_days'] . '天已有条数):'
+ . implode('、', array_map(fn($u) => $u . '(' . ($fair['counts'][$u] ?? 0) . ')', $orderedUsers)) . '');
+ $n = count($orderedUsers);
foreach ($keep as $i => &$row) {
- $row['new_user_id'] = $targetUserIds[$i % $n];
+ $row['new_user_id'] = $orderedUsers[$i % $n];
}
unset($row);
$groups = [];
diff --git a/app/command/HesuGoogleInquiryImportCommand.php b/app/command/HesuGoogleInquiryImportCommand.php
index c1b4350..bcfa61e 100644
--- a/app/command/HesuGoogleInquiryImportCommand.php
+++ b/app/command/HesuGoogleInquiryImportCommand.php
@@ -3,6 +3,7 @@
namespace app\command;
use app\common\model\CrmCustomer;
+use app\common\utils\InquiryFairAssigner;
use app\common\utils\email\InquiryDigestMail;
use app\common\utils\email\MailSend;
use PhpOffice\PhpSpreadsheet\IOFactory;
@@ -191,10 +192,14 @@ class HesuGoogleInquiryImportCommand extends Command
$output->writeln(' 无联系方式 行' . $row['excel_row'] . ' ' . $row['contacts'] . '');
}
- // 轮询分配(按行序 i % n)
- $n = count($targetUserIds);
+ // 公平分配:按近10天窗口内实际分到数升序(少者优先、最久未分到优先),再按序轮询
+ $fair = InquiryFairAssigner::fairOrder($targetUserIds);
+ $orderedUsers = $fair['ordered'];
+ $output->writeln('分配顺序(近' . $fair['window_days'] . '天已有条数):'
+ . implode('、', array_map(fn($u) => $u . '(' . ($fair['counts'][$u] ?? 0) . ')', $orderedUsers)) . '');
+ $n = count($orderedUsers);
foreach ($keep as $i => &$row) {
- $row['new_user_id'] = $targetUserIds[$i % $n];
+ $row['new_user_id'] = $orderedUsers[$i % $n];
}
unset($row);
$groups = [];
diff --git a/app/command/HesuGoogleWhatsAppImportCommand.php b/app/command/HesuGoogleWhatsAppImportCommand.php
index afdc2ad..f04bb1c 100644
--- a/app/command/HesuGoogleWhatsAppImportCommand.php
+++ b/app/command/HesuGoogleWhatsAppImportCommand.php
@@ -4,6 +4,7 @@ namespace app\command;
use app\common\model\CrmCustomer;
use app\common\service\OssService;
+use app\common\utils\InquiryFairAssigner;
use app\common\utils\email\InquiryDigestMail;
use app\common\utils\email\MailSend;
use PhpOffice\PhpSpreadsheet\IOFactory;
@@ -219,10 +220,14 @@ class HesuGoogleWhatsAppImportCommand extends Command
}
$output->writeln('截图: 找到 ' . $shotFound . ' / 缺失 ' . $shotMissing . '(目录: ' . $imagesDir . ')');
- // 轮询分配(按行序 i % n)
- $n = count($targetUserIds);
+ // 公平分配:按近10天窗口内实际分到数升序(少者优先、最久未分到优先),再按序轮询
+ $fair = InquiryFairAssigner::fairOrder($targetUserIds);
+ $orderedUsers = $fair['ordered'];
+ $output->writeln('分配顺序(近' . $fair['window_days'] . '天已有条数):'
+ . implode('、', array_map(fn($u) => $u . '(' . ($fair['counts'][$u] ?? 0) . ')', $orderedUsers)) . '');
+ $n = count($orderedUsers);
foreach ($keep as $i => &$row) {
- $row['new_user_id'] = $targetUserIds[$i % $n];
+ $row['new_user_id'] = $orderedUsers[$i % $n];
}
unset($row);
$groups = [];
diff --git a/app/common/utils/InquiryFairAssigner.php b/app/common/utils/InquiryFairAssigner.php
new file mode 100644
index 0000000..46e9011
--- /dev/null
+++ b/app/common/utils/InquiryFairAssigner.php
@@ -0,0 +1,66 @@
+, 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];
+ }
+}