diff --git a/admin/src/views/consumer/prescription/order_list.vue b/admin/src/views/consumer/prescription/order_list.vue index f7930db7..88c7a508 100644 --- a/admin/src/views/consumer/prescription/order_list.vue +++ b/admin/src/views/consumer/prescription/order_list.vue @@ -277,7 +277,7 @@ :fetch-fun="prescriptionOrderExport" :params="prescriptionOrderExportParams" :page-size="pager.size" - export-hint="导出范围与上方筛选一致(履约状态、创建时间及其他条件均会生效)。含「自媒体渠道(挂号渠道来源)」:按诊单关联患者取最近一条挂号的渠道字典与细分。" + export-hint="导出范围与上方筛选一致(履约状态、创建时间及其他条件均会生效)。含「自媒体渠道(挂号渠道来源)」:优先取该单关联处方登记的挂号;无则诊单下同患者挂号取 id 最大的一条(与前台挂号选择的记录一致);业绩侧栏带渠道筛选导出时与同页列表高亮挂号同源。" /> diff --git a/server/app/adminapi/lists/tcm/PrescriptionOrderLists.php b/server/app/adminapi/lists/tcm/PrescriptionOrderLists.php index ae38a118..8acbadbe 100644 --- a/server/app/adminapi/lists/tcm/PrescriptionOrderLists.php +++ b/server/app/adminapi/lists/tcm/PrescriptionOrderLists.php @@ -596,7 +596,7 @@ class PrescriptionOrderLists extends BaseAdminDataLists implements ListsSearchIn } if ((int) $this->export === ExportEnum::EXPORT) { - PrescriptionOrderLogic::appendPrescriptionOrderListExportRows($lists, $this->adminInfo); + PrescriptionOrderLogic::appendPrescriptionOrderListExportRows($lists, $this->adminInfo, $this->params); } return $lists; diff --git a/server/app/adminapi/logic/tcm/PrescriptionOrderLogic.php b/server/app/adminapi/logic/tcm/PrescriptionOrderLogic.php index 63fbedf6..072e0dfe 100644 --- a/server/app/adminapi/logic/tcm/PrescriptionOrderLogic.php +++ b/server/app/adminapi/logic/tcm/PrescriptionOrderLogic.php @@ -2602,10 +2602,12 @@ class PrescriptionOrderLogic /** * 业务订单列表导出:写入与 PrescriptionOrderLists::setExcelFields 对应的字段(export=2 时由列表类调用) + * 「挂号渠道来源」取值与详情/列表解析一致:处方 appointment_id → 否则诊单下 MAX(挂号.id);业绩抽屉带渠道时与列表同源高亮。 * * @param array> $lists + * @param array $listsParams PrescriptionOrderLists 请求参数(含 yeji_order_drawer、channel_code) */ - public static function appendPrescriptionOrderListExportRows(array &$lists, array $adminInfo): void + public static function appendPrescriptionOrderListExportRows(array &$lists, array $adminInfo, array $listsParams = []): void { if ($lists === []) { return; @@ -2639,43 +2641,17 @@ class PrescriptionOrderLogic } } - /** 诊单 ID => 该患者最近一条挂号(按预约日、id 倒序),用于导出「挂号渠道来源」 */ - $apptChannelByDiagId = []; - $channelNameByValue = []; $chCols = self::doctorAppointmentChannelColumnsForExport(); $needGuahaoChannel = $chCols['channel_source'] || $chCols['channels'] || $chCols['channel_source_detail']; - if ($diagIdList !== [] && $needGuahaoChannel) { - $selectFields = ['patient_id', 'appointment_date', 'id']; - if ($chCols['channel_source']) { - $selectFields[] = 'channel_source'; - } - if ($chCols['channel_source_detail']) { - $selectFields[] = 'channel_source_detail'; - } - if ($chCols['channels']) { - $selectFields[] = 'channels'; - } - $apptRows = Appointment::whereIn('patient_id', $diagIdList) - ->field($selectFields) - ->order('appointment_date', 'desc') - ->order('id', 'desc') - ->select() - ->toArray(); - foreach ($apptRows as $ar) { - $p = (int) ($ar['patient_id'] ?? 0); - if ($p > 0 && !isset($apptChannelByDiagId[$p])) { - $apptChannelByDiagId[$p] = $ar; - } - } - if ($chCols['channel_source'] || $chCols['channels']) { - $channelNameByValue = DictData::where('type_value', 'channels')->column('name', 'value'); - } - } + $channelNameByValue = []; + $apptById = []; + /** @var array $resolvedApptIdByPoId 订单 id → 用于导出渠道的那条挂号 id */ + $resolvedApptIdByPoId = []; $rxById = []; if ($rxIdList !== []) { $rxRows = Prescription::whereIn('id', $rxIdList)->whereNull('delete_time') - ->field(['id', 'prescription_type', 'need_decoction', 'dose_unit', 'assistant_id']) + ->field(['id', 'prescription_type', 'need_decoction', 'dose_unit', 'assistant_id', 'appointment_id']) ->select() ->toArray(); foreach ($rxRows as $xr) { @@ -2683,6 +2659,102 @@ class PrescriptionOrderLogic } } + if ($needGuahaoChannel) { + $yejiChannelHighlightByDiag = []; + if ( + (int) ($listsParams['yeji_order_drawer'] ?? 0) === 1 + && trim((string) ($listsParams['channel_code'] ?? '')) !== '' + ) { + $allDiagIdsForYeji = array_values(array_unique(array_filter( + array_map(static fn ($x): int => (int) ($x['diagnosis_id'] ?? 0), $lists), + static fn (int $id): bool => $id > 0 + ))); + if ($allDiagIdsForYeji !== []) { + $yejiChannelHighlightByDiag = YejiStatsLogic::batchResolveYejiChannelDrawerHighlightAppointmentIds( + $allDiagIdsForYeji, + $listsParams + ); + } + } + + $diagNeedFallback = []; + foreach ($lists as $item) { + $rxId = (int) ($item['prescription_id'] ?? 0); + $dgId = (int) ($item['diagnosis_id'] ?? 0); + $apFromRx = $rxId > 0 ? (int) (($rxById[$rxId] ?? [])['appointment_id'] ?? 0) : 0; + if ($apFromRx <= 0 && $dgId > 0) { + $diagNeedFallback[$dgId] = true; + } + } + $fallbackDiagIds = array_keys($diagNeedFallback); + $latestApptByDiag = []; + if ($fallbackDiagIds !== []) { + try { + $agg = Db::name('doctor_appointment') + ->whereIn('patient_id', $fallbackDiagIds) + ->fieldRaw('patient_id, MAX(id) as max_id') + ->group('patient_id') + ->select() + ->toArray(); + foreach ($agg as $r) { + $pid = (int) ($r['patient_id'] ?? 0); + $mid = (int) ($r['max_id'] ?? 0); + if ($pid > 0 && $mid > 0) { + $latestApptByDiag[$pid] = $mid; + } + } + } catch (\Throwable) { + $latestApptByDiag = []; + } + } + + foreach ($lists as $item) { + $poRowId = (int) ($item['id'] ?? 0); + if ($poRowId <= 0) { + continue; + } + $rxId = (int) ($item['prescription_id'] ?? 0); + $dgId = (int) ($item['diagnosis_id'] ?? 0); + $rxApptId = $rxId > 0 ? (int) (($rxById[$rxId] ?? [])['appointment_id'] ?? 0) : 0; + $resolved = $rxApptId; + if ($resolved <= 0 && $dgId > 0) { + $resolved = (int) ($latestApptByDiag[$dgId] ?? 0); + } + $preferredYeji = $dgId > 0 ? (int) ($yejiChannelHighlightByDiag[$dgId] ?? 0) : 0; + if ($preferredYeji > 0) { + $resolved = $preferredYeji; + } + if ($resolved > 0) { + $resolvedApptIdByPoId[$poRowId] = $resolved; + } + } + + $uniqApptIds = array_values(array_unique(array_values($resolvedApptIdByPoId))); + if ($uniqApptIds !== []) { + $selectFields = ['id']; + if ($chCols['channel_source']) { + $selectFields[] = 'channel_source'; + } + if ($chCols['channel_source_detail']) { + $selectFields[] = 'channel_source_detail'; + } + if ($chCols['channels']) { + $selectFields[] = 'channels'; + } + $apptRows = Appointment::whereIn('id', $uniqApptIds)->field($selectFields)->select()->toArray(); + foreach ($apptRows as $ar) { + $aid = (int) ($ar['id'] ?? 0); + if ($aid > 0) { + $apptById[$aid] = $ar; + } + } + } + + if ($chCols['channel_source'] || $chCols['channels']) { + $channelNameByValue = DictData::where('type_value', 'channels')->column('name', 'value'); + } + } + $logRows = PrescriptionOrderLog::whereIn('prescription_order_id', $poIds) ->whereIn('action', ['audit_rx_approve', 'audit_rx_reject', 'revoke_rx_audit']) ->field(['prescription_order_id', 'id', 'action', 'admin_name', 'create_time']) @@ -2745,7 +2817,8 @@ class PrescriptionOrderLogic $item['export_medication_form'] = self::formatMedicationFormForExport(\is_array($rx) ? $rx : []); $item['export_channel'] = (string) ($item['service_channel'] ?? ''); - $apCh = $apptChannelByDiagId[$diagId] ?? null; + $apptIdResolved = $resolvedApptIdByPoId[$poId] ?? 0; + $apCh = ($apptIdResolved > 0 && isset($apptById[$apptIdResolved])) ? $apptById[$apptIdResolved] : null; $item['export_guahao_channel_source'] = \is_array($apCh) ? self::formatGuahaoChannelSourceForExport($apCh, $channelNameByValue) : '';