From f773e73de652afabd44a917b9b9ddd5e787eb48c Mon Sep 17 00:00:00 2001 From: ShengLong <452591453@qq.com> Date: Wed, 22 Apr 2026 11:28:21 +0800 Subject: [PATCH] Update ConversionLogic.php --- .../adminapi/logic/stats/ConversionLogic.php | 142 ++++++++---------- 1 file changed, 62 insertions(+), 80 deletions(-) diff --git a/server/app/adminapi/logic/stats/ConversionLogic.php b/server/app/adminapi/logic/stats/ConversionLogic.php index cc369e66..390d0785 100644 --- a/server/app/adminapi/logic/stats/ConversionLogic.php +++ b/server/app/adminapi/logic/stats/ConversionLogic.php @@ -327,100 +327,82 @@ class ConversionLogic int $startTimestamp, int $endTimestamp ): void { - $wxUserIdToAdminIds = self::loadWorkWechatAdminMap(); - $rows = Db::name('qywx_external_contact') - ->whereNull('delete_time') - ->whereRaw( - '((external_first_add_time BETWEEN ? AND ?) OR (external_first_add_time = 0 AND create_time BETWEEN ? AND ?))', - [$startTimestamp, $endTimestamp, $startTimestamp, $endTimestamp] - ) - ->field('follow_admin_ids, follow_users') - ->select() - ->toArray(); + $timeSql = '((q.external_first_add_time BETWEEN ? AND ?) OR (q.external_first_add_time = 0 AND q.create_time BETWEEN ? AND ?))'; + $bind = [$startTimestamp, $endTimestamp, $startTimestamp, $endTimestamp]; + $indexSql = self::buildJsonIndexUnionSql(32); - $countsByAdmin = []; - foreach ($rows as $row) { - $adminIds = self::extractFollowAdminIds($row, $wxUserIdToAdminIds); - if ($adminIds === []) { + // 优先使用 follow_admin_ids(JSON 数组) 做 SQL 聚合,兼容不支持 JSON_TABLE 的 MySQL 版本。 + $countsByAdmin = Db::query( + << idx.n + AND {$timeSql} +GROUP BY admin_id +SQL, + $bind + ); + + $mergedCounts = []; + foreach ($countsByAdmin as $row) { + $adminId = (int) ($row['admin_id'] ?? 0); + if ($adminId <= 0) { continue; } - - foreach ($adminIds as $adminId) { - $countsByAdmin[$adminId] = ($countsByAdmin[$adminId] ?? 0) + 1; - } + $mergedCounts[$adminId] = ($mergedCounts[$adminId] ?? 0) + (int) ($row['cnt'] ?? 0); } - foreach ($countsByAdmin as $adminId => $count) { + // 兼容历史数据:follow_admin_ids 为空时,再从 follow_users(JSON) -> admin.work_wechat_userid 回填。 + $fallbackRows = Db::query( + << idx.n +JOIN zyt_admin a + ON a.work_wechat_userid = JSON_UNQUOTE(JSON_EXTRACT(q.follow_users, CONCAT('$[', idx.n, '].userid'))) + AND a.delete_time IS NULL +WHERE q.delete_time IS NULL + AND COALESCE(JSON_LENGTH(q.follow_admin_ids), 0) = 0 + AND {$timeSql} +GROUP BY a.id +SQL, + $bind + ); + + foreach ($fallbackRows as $row) { + $adminId = (int) ($row['admin_id'] ?? 0); + if ($adminId <= 0) { + continue; + } + $mergedCounts[$adminId] = ($mergedCounts[$adminId] ?? 0) + (int) ($row['cnt'] ?? 0); + } + + foreach ($mergedCounts as $adminId => $count) { foreach (self::mapEntityIds($dimension, (int) $adminId, $entityIds, $adminToDeptIds) as $entityId) { $entities[$entityId]['add_fans_count'] += (int) $count; } } } - /** - * @return array - */ - private static function loadWorkWechatAdminMap(): array + private static function buildJsonIndexUnionSql(int $maxIndex): string { - $rows = Db::name('admin') - ->whereNull('delete_time') - ->where('work_wechat_userid', '<>', '') - ->field('id, work_wechat_userid') - ->select() - ->toArray(); - - $map = []; - foreach ($rows as $row) { - $userId = trim((string)($row['work_wechat_userid'] ?? '')); - $adminId = (int)($row['id'] ?? 0); - if ($userId === '' || $adminId <= 0) { - continue; - } - $map[$userId] ??= []; - $map[$userId][] = $adminId; + $parts = []; + for ($i = 0; $i < $maxIndex; $i++) { + $parts[] = 'SELECT ' . $i . ' AS n'; } - return $map; - } - - /** - * @param array $row - * @param array $wxUserIdToAdminIds - * @return int[] - */ - private static function extractFollowAdminIds(array $row, array $wxUserIdToAdminIds): array - { - $adminIds = json_decode((string)($row['follow_admin_ids'] ?? '[]'), true); - if (is_array($adminIds)) { - $adminIds = array_values(array_unique(array_filter(array_map('intval', $adminIds), static fn (int $id): bool => $id > 0))); - } else { - $adminIds = []; - } - - if ($adminIds !== []) { - return $adminIds; - } - - $followUsers = json_decode((string)($row['follow_users'] ?? '[]'), true); - if (!is_array($followUsers)) { - return []; - } - - $resolved = []; - foreach ($followUsers as $followUser) { - if (!is_array($followUser)) { - continue; - } - $userId = trim((string)($followUser['userid'] ?? '')); - if ($userId === '' || !isset($wxUserIdToAdminIds[$userId])) { - continue; - } - foreach ($wxUserIdToAdminIds[$userId] as $adminId) { - $resolved[$adminId] = $adminId; - } - } - - return array_values($resolved); + return implode(' UNION ALL ', $parts); } /**