diff --git a/admin/src/views/fans/yeji.vue b/admin/src/views/fans/yeji.vue index 3b71a5f0..b629479b 100644 --- a/admin/src/views/fans/yeji.vue +++ b/admin/src/views/fans/yeji.vue @@ -1236,6 +1236,7 @@ + diff --git a/server/app/adminapi/lists/tcm/PrescriptionOrderLists.php b/server/app/adminapi/lists/tcm/PrescriptionOrderLists.php index 1a07be15..acd0f666 100755 --- a/server/app/adminapi/lists/tcm/PrescriptionOrderLists.php +++ b/server/app/adminapi/lists/tcm/PrescriptionOrderLists.php @@ -919,7 +919,8 @@ class PrescriptionOrderLists extends BaseAdminDataLists implements ListsSearchIn YejiStatsLogic::applyPrescriptionOrderListAlignedWinnerDeptFilter( $query, (int) $this->params['assistant_dept_id'], - $yejiTableRowDeptIds + $yejiTableRowDeptIds, + $this->params['dept_ids'] ?? null ); return; diff --git a/server/app/adminapi/logic/stats/YejiStatsLogic.php b/server/app/adminapi/logic/stats/YejiStatsLogic.php index 50914348..9864e76d 100755 --- a/server/app/adminapi/logic/stats/YejiStatsLogic.php +++ b/server/app/adminapi/logic/stats/YejiStatsLogic.php @@ -2510,6 +2510,7 @@ class YejiStatsLogic 'patient_name' => (string) ($rw['patient_name'] ?? ''), 'patient_phone' => (string) ($rw['patient_phone'] ?? ''), 'doctor_name' => (string) ($rw['doctor_name'] ?? ''), + 'assistant_name' => (string) ($rw['assistant_name'] ?? ''), 'channel_source' => $hasChSrc ? (string) ($rw['channel_source'] ?? '') : '', ]; } @@ -2596,6 +2597,8 @@ class YejiStatsLogic $q = Db::name('doctor_appointment')->alias('a') ->leftJoin('tcm_diagnosis u', 'a.patient_id = u.id') ->leftJoin('admin doc', 'a.doctor_id = doc.id AND doc.delete_time IS NULL') + ->leftJoin('admin appt_asst', 'a.assistant_id = appt_asst.id AND appt_asst.delete_time IS NULL') + ->leftJoin('admin diag_asst', 'u.assistant_id = diag_asst.id AND diag_asst.delete_time IS NULL') ->whereBetween('a.appointment_date', [$startDate, $endDate]) ->whereIn('a.status', [1, 3, 4]) ->whereRaw('(u.id IS NULL OR u.delete_time IS NULL)'); @@ -2638,6 +2641,7 @@ class YejiStatsLogic 'u.patient_name', 'u.phone AS patient_phone', 'doc.name AS doctor_name', + 'COALESCE(appt_asst.name, diag_asst.name) AS assistant_name', ]; if ($hasChSrc) { $fieldParts[] = 'a.channel_source'; @@ -2654,7 +2658,7 @@ class YejiStatsLogic $lists = self::formatYejiAppointmentLinePayloadRows($rawList, $hasChSrc); - $note = '与业绩表「预约诊单」列同口径:预约日期在统计区间内,状态为已预约 / 已完成 / 已过号(不含已取消);部门归属医助优先,否则接诊医生。'; + $note = '与业绩表「预约诊单」列同口径:预约日期在统计区间内,状态为已预约 / 已完成 / 已过号(不含已取消);部门归属医助优先,否则接诊医生;医助名与统计口径一致(挂号创建医助优先,否则诊单医助)。'; return [ 'start_date' => (string) $c['startDate'], @@ -2794,6 +2798,8 @@ class YejiStatsLogic $q = Db::name('doctor_appointment')->alias('a') ->leftJoin('tcm_diagnosis u', 'a.patient_id = u.id') ->leftJoin('admin doc', 'a.doctor_id = doc.id AND doc.delete_time IS NULL') + ->leftJoin('admin appt_asst', 'a.assistant_id = appt_asst.id AND appt_asst.delete_time IS NULL') + ->leftJoin('admin diag_asst', 'u.assistant_id = diag_asst.id AND diag_asst.delete_time IS NULL') ->whereBetween('a.appointment_date', [$startDate, $endDate]) ->whereIn('a.status', [1, 3, 4]) ->whereRaw('(u.id IS NULL OR u.delete_time IS NULL)') @@ -2824,6 +2830,7 @@ class YejiStatsLogic 'u.patient_name', 'u.phone AS patient_phone', 'doc.name AS doctor_name', + 'COALESCE(appt_asst.name, diag_asst.name) AS assistant_name', ]; if ($hasChSrc) { $fieldParts[] = 'a.channel_source'; @@ -2841,7 +2848,7 @@ class YejiStatsLogic $lists = self::formatYejiAppointmentLinePayloadRows($rawList, $hasChSrc); $note = '与排行榜「预约诊单」同口径:预约日期在统计区间内,状态为已预约 / 已完成 / 已过号(不含已取消);' - . '有效医助优先取挂号表创建医助,否则取诊单医助。'; + . '有效医助优先取挂号表创建医助,否则取诊单医助(表中「医助」列与此一致)。'; return [ 'start_date' => (string) $c['startDate'], @@ -3400,6 +3407,88 @@ class YejiStatsLogic return array_values(array_unique($out)); } + /** + * 处方订单列表(yeji_order_drawer=1 + yeji_table_row_dept_ids):assistant_dept_id 部门筛选与 {@see aggregateListAlignedOrderMetricsByDept} + * 一致——仅按订单创建人人事部门映射到当前表格展示行,命中多行取最深;只保留映射结果为 $winnerDeptId 的订单。 + * + * @param Query $query tcm_prescription_order 主查询(无表别名) + * @param int[] $yejiTableRowDeptIds 请求 yeji_table_row_dept_ids + * @param int|string|array|array|null $yejiDeptIdsParam 请求 dept_ids,传入 {@see resolvePrimaryDepts} + */ + public static function applyPrescriptionOrderListAlignedWinnerDeptFilter( + Query $query, + int $winnerDeptId, + array $yejiTableRowDeptIds, + $yejiDeptIdsParam = null + ): void { + $winnerDeptId = (int) $winnerDeptId; + $tableRowDeptIds = array_values(array_unique(array_filter(array_map('intval', $yejiTableRowDeptIds), static function (int $x): bool { + return $x > 0; + }))); + if ($winnerDeptId <= 0 || $tableRowDeptIds === []) { + $query->whereRaw('0 = 1'); + + return; + } + if (!in_array($winnerDeptId, $tableRowDeptIds, true)) { + $query->whereRaw('0 = 1'); + + return; + } + + [$primaryDeptIds, , , $deptById] = self::resolvePrimaryDepts($yejiDeptIdsParam); + $deptToDescendants = self::buildDeptDescendants($primaryDeptIds); + $adminToPrimary = self::buildAdminToPrimaryDept($primaryDeptIds, $deptToDescendants); + + $childrenOf = self::yejiFullDeptChildrenOf(); + /** @var array> $rowSubtreeFlips */ + $rowSubtreeFlips = []; + foreach ($tableRowDeptIds as $rid) { + $rid = (int) $rid; + if ($rid > 0) { + $rowSubtreeFlips[$rid] = self::yejiDeptSubtreeIdFlip($rid, $childrenOf); + } + } + + $links = Db::name('admin_dept')->field(['admin_id', 'dept_id'])->select()->toArray(); + /** @var array $adminDeptIdList */ + $adminDeptIdList = []; + foreach ($links as $l) { + $aid = (int) $l['admin_id']; + $did = (int) $l['dept_id']; + if ($aid > 0 && $did > 0) { + $adminDeptIdList[$aid][] = $did; + } + } + + $candidateIds = array_values(array_unique(array_merge(array_keys($adminDeptIdList), array_keys($adminToPrimary)))); + $allowedCreators = []; + foreach ($candidateIds as $aid) { + $aid = (int) $aid; + if ($aid <= 0) { + continue; + } + $mapped = self::resolveDeepestYejiTableRowForListDeptOr( + [$aid => true], + $adminDeptIdList, + $rowSubtreeFlips, + $tableRowDeptIds, + $deptById, + $adminToPrimary + ); + if ($mapped === $winnerDeptId) { + $allowedCreators[] = $aid; + } + } + $allowedCreators = array_values(array_unique(array_filter($allowedCreators, static fn (int $x): bool => $x > 0))); + if ($allowedCreators === []) { + $query->whereRaw('0 = 1'); + + return; + } + $query->whereIn('creator_id', $allowedCreators); + } + /** * 标签/医助兜底口径下的渠道向业绩全量 SUM(与 sumPerformance 的 scoped 分支同一组 WHERE,无部门归属过滤)。 */