From 79203d948e75e19a83ecc5f4abffbfca4026d13f Mon Sep 17 00:00:00 2001 From: ShengLong <452591453@qq.com> Date: Thu, 7 May 2026 12:16:50 +0800 Subject: [PATCH 1/2] Update ConversionLogic.php --- .../adminapi/logic/stats/ConversionLogic.php | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/server/app/adminapi/logic/stats/ConversionLogic.php b/server/app/adminapi/logic/stats/ConversionLogic.php index 49136ffa..aadd5e0b 100644 --- a/server/app/adminapi/logic/stats/ConversionLogic.php +++ b/server/app/adminapi/logic/stats/ConversionLogic.php @@ -9,6 +9,7 @@ use app\adminapi\logic\tcm\DiagnosisLogic; use app\common\model\finance\AccountCost; use app\common\service\DataScope\DataScopeService; use app\common\service\qywx\MediaChannelService; +use think\db\Query; use think\facade\Db; class ConversionLogic @@ -904,10 +905,16 @@ class ConversionLogic ->leftJoin('tcm_diagnosis u', 'a.patient_id = u.id') ->where('a.appointment_date', '>=', $startDate) ->where('a.appointment_date', '<=', $endDate) - ->whereRaw('(u.id IS NULL OR u.delete_time IS NULL)') ->fieldRaw("{$sourceExpr} AS source_admin_id, a.patient_id AS diagnosis_id, COUNT(*) AS appointment_count, SUM(CASE WHEN a.status = 3 THEN 1 ELSE 0 END) AS interview_count") ->group("{$sourceExpr}, a.patient_id"); + $query->where(static function (Query $subQuery): void { + $subQuery->whereNull('u.id') + ->whereOr(static function (Query $orQuery): void { + $orQuery->whereNull('u.delete_time'); + }); + }); + if ($mediaChannel !== null) { $legacyChannelValues = MediaChannelService::getLegacyAppointmentChannelValues($mediaChannel); if ($legacyChannelValues !== []) { @@ -976,7 +983,9 @@ class ConversionLogic ->where('o.status', 2) ->where('o.order_type', 1) ->where('o.amount', 5) - ->whereRaw('(o.payment_time IS NOT NULL AND o.payment_time <> "" AND o.payment_time >= ? AND o.payment_time <= ?)', [$startDateTime, $endDateTime]) + ->whereNotNull('o.payment_time') + ->where('o.payment_time', '<>', '') + ->whereBetweenTime('o.payment_time', $startDateTime, $endDateTime) ->fieldRaw('o.creator_id AS source_admin_id, COUNT(*) AS paid_appointment_count') ->group('o.creator_id'); @@ -1896,7 +1905,8 @@ class ConversionLogic // 单条 LIKE 没命中再退化全表(量大时会慢,因此仅在极少数员工场景下兜底)。 $followRows = Db::name('qywx_external_contact') ->whereNull('delete_time') - ->whereRaw('follow_users IS NOT NULL AND follow_users <> ""') + ->whereNotNull('follow_users') + ->where('follow_users', '<>', '') ->limit(2000) ->field('follow_users') ->select() @@ -2385,4 +2395,5 @@ class ConversionLogic return round($numerator / $denominator, 2); } + } From 755491c263fd6d5898b1ee9eca12a0299b78c4b7 Mon Sep 17 00:00:00 2001 From: ShengLong <452591453@qq.com> Date: Thu, 7 May 2026 12:44:43 +0800 Subject: [PATCH 2/2] Update ConversionLogic.php --- .../adminapi/logic/stats/ConversionLogic.php | 100 ++++++++++-------- 1 file changed, 53 insertions(+), 47 deletions(-) diff --git a/server/app/adminapi/logic/stats/ConversionLogic.php b/server/app/adminapi/logic/stats/ConversionLogic.php index aadd5e0b..45e44247 100644 --- a/server/app/adminapi/logic/stats/ConversionLogic.php +++ b/server/app/adminapi/logic/stats/ConversionLogic.php @@ -69,8 +69,6 @@ class ConversionLogic $entities = self::loadEntities($dimension, $params, $visibleAdminIds); $entityIds = array_keys($entities); - $allocationEntities = self::loadEntities($dimension, $params, $visibleAdminIds); - $allocationEntityIds = array_keys($allocationEntities); if ($entityIds === []) { $result = [ @@ -97,8 +95,9 @@ class ConversionLogic } $adminToDeptIds = self::loadAdminDeptMap(); - self::hydrateFanStats($allocationEntities, $dimension, $allocationEntityIds, $adminToDeptIds, $startTimestamp, $endTimestamp, $mediaChannel, $visibleAdminIds); self::hydrateFanStats($entities, $dimension, $entityIds, $adminToDeptIds, $startTimestamp, $endTimestamp, $mediaChannel, $visibleAdminIds); + $allocationEntities = $entities; + $allocationEntityIds = $entityIds; self::hydrateAppointmentStats($entities, $dimension, $entityIds, $adminToDeptIds, $startTimestamp, $endTimestamp, $startDate, $endDate, $mediaChannel, $visibleAdminIds); self::hydrateOrderAndAmountStats($entities, $dimension, $entityIds, $adminToDeptIds, $startTimestamp, $endTimestamp, $mediaChannel, $visibleAdminIds); // 数据隔离:可见部门 = 可见 admin 所属部门并集;用于 account_cost 与下游 cost 分摊。 @@ -258,11 +257,13 @@ class ConversionLogic ?array $adminInfo = null ): array { + $allowedDeptIds = self::resolveFilterAllowedDeptIds($visibleAdminIds, $eligibleDeptIds); + return [ - 'departments' => self::buildDepartmentOptions($visibleAdminIds, $eligibleDeptIds), + 'departments' => self::buildDepartmentOptions($visibleAdminIds, $eligibleDeptIds, $allowedDeptIds), 'assistants' => DiagnosisLogic::getAssistants($adminId, $adminInfo), 'doctors' => self::buildDoctorOptions($visibleAdminIds), - 'media_channels' => self::buildMediaChannelOptions($visibleAdminIds, $eligibleDeptIds), + 'media_channels' => self::buildMediaChannelOptions($visibleAdminIds, $eligibleDeptIds, $allowedDeptIds), ]; } @@ -273,36 +274,19 @@ class ConversionLogic * * @return array> */ - private static function buildDepartmentOptions(?array $visibleAdminIds, array $eligibleDeptIds): array + private static function buildDepartmentOptions(?array $visibleAdminIds, array $eligibleDeptIds, ?array $allowedDeptIds = null): array { $allTree = DeptLogic::getAllData(); if ($visibleAdminIds === null) { return $allTree; } - $allowedDeptIds = []; - if ($visibleAdminIds !== []) { - $deptIds = Db::name('admin_dept') - ->whereIn('admin_id', $visibleAdminIds) - ->column('dept_id'); - foreach ($deptIds as $deptId) { - $deptId = (int)$deptId; - if ($deptId > 0) { - $allowedDeptIds[$deptId] = true; - } - } - } - foreach ($eligibleDeptIds as $deptId) { - $deptId = (int)$deptId; - if ($deptId > 0) { - $allowedDeptIds[$deptId] = true; - } - } + $allowedDeptIds ??= self::resolveFilterAllowedDeptIds($visibleAdminIds, $eligibleDeptIds); if ($allowedDeptIds === []) { return []; } - return self::filterDeptTreeByIds($allTree, array_keys($allowedDeptIds)); + return self::filterDeptTreeByIds($allTree, $allowedDeptIds); } /** @@ -341,7 +325,7 @@ class ConversionLogic * * @return array> */ - private static function buildMediaChannelOptions(?array $visibleAdminIds, array $eligibleDeptIds): array + private static function buildMediaChannelOptions(?array $visibleAdminIds, array $eligibleDeptIds, ?array $allowedDeptIds = null): array { $allOptions = MediaChannelService::getOptions(); if ($visibleAdminIds === null) { @@ -351,30 +335,13 @@ class ConversionLogic return $allOptions; } - $allowedDeptIds = []; - if ($visibleAdminIds !== []) { - $deptIds = Db::name('admin_dept') - ->whereIn('admin_id', $visibleAdminIds) - ->column('dept_id'); - foreach ($deptIds as $deptId) { - $deptId = (int)$deptId; - if ($deptId > 0) { - $allowedDeptIds[$deptId] = true; - } - } - } - foreach ($eligibleDeptIds as $deptId) { - $deptId = (int)$deptId; - if ($deptId > 0) { - $allowedDeptIds[$deptId] = true; - } - } + $allowedDeptIds ??= self::resolveFilterAllowedDeptIds($visibleAdminIds, $eligibleDeptIds); if ($allowedDeptIds === []) { return []; } $allowedCodes = Db::name('account_cost') - ->whereIn('dept_id', array_keys($allowedDeptIds)) + ->whereIn('dept_id', $allowedDeptIds) ->where('media_channel_code', '<>', '') ->distinct(true) ->column('media_channel_code'); @@ -832,8 +799,14 @@ class ConversionLogic ->leftJoin('admin a', 'a.work_wechat_userid = e.user_id AND a.delete_time IS NULL') ->where('e.change_type', 'add_external_contact') ->where('e.event_time', 'between', [$startTimestamp, $endTimestamp]) - ->fieldRaw('e.user_id, a.id AS admin_id, COUNT(*) AS add_fans_count') - ->group('e.user_id, a.id'); + ->fieldRaw('a.id AS admin_id, COUNT(*) AS add_fans_count') + ->group('a.id'); + + if ($visibleAdminIds !== null) { + $query->whereIn('a.id', $visibleAdminIds); + } elseif ($dimension !== 'dept' && $entityIds !== []) { + $query->whereIn('a.id', $entityIds); + } if ($mediaChannel !== null) { $query->leftJoin('qywx_external_contact q', 'q.external_userid = e.external_userid'); @@ -2396,4 +2369,37 @@ class ConversionLogic return round($numerator / $denominator, 2); } + /** + * @param int[]|null $visibleAdminIds + * @param int[] $eligibleDeptIds + * @return int[] + */ + private static function resolveFilterAllowedDeptIds(?array $visibleAdminIds, array $eligibleDeptIds): array + { + if ($visibleAdminIds === null) { + return array_values(array_unique(array_filter(array_map('intval', $eligibleDeptIds), static fn (int $deptId): bool => $deptId > 0))); + } + + $allowedDeptIds = []; + if ($visibleAdminIds !== []) { + $deptIds = Db::name('admin_dept') + ->whereIn('admin_id', $visibleAdminIds) + ->column('dept_id'); + foreach ($deptIds as $deptId) { + $deptId = (int)$deptId; + if ($deptId > 0) { + $allowedDeptIds[$deptId] = $deptId; + } + } + } + foreach ($eligibleDeptIds as $deptId) { + $deptId = (int)$deptId; + if ($deptId > 0) { + $allowedDeptIds[$deptId] = $deptId; + } + } + + return array_values($allowedDeptIds); + } + }