startDate->copy()->startOfYear()->format('Y-m-d'); $periodMigrationFilter = function ($q) use ($departmentId, $dateRange, $startYear) { $q->where('department_id', $departmentId) ->where('ingoing_date', '<=', $dateRange->endSql()) ->where(function ($sub) use ($dateRange, $startYear) { // Миграции без out_date (еще лежат) $sub->whereNull('out_date') ->where('ingoing_date', '>', $startYear); // Миграции с out_date (закрытые) $sub->orWhere(function ($sub2) use ($dateRange, $startYear) { $sub2->whereNotNull('out_date') ->where('out_date', '>', $dateRange->startSql()) ->where('out_date', '>', $startYear); }); }); }; $departmentMigrationFilter = function ($q) use ($departmentId) { $q->where('department_id', $departmentId) ->orderByDesc('ingoing_date'); }; // 1. Один запрос: получаем "сырые" данные (без вычисляемых статусов) $all = ReportDutyPatient::query() ->when($reportIds, function ($query, $reportIds) { return $query->whereIn('report_duty_id', $reportIds); }) ->whereHas('migrations', $periodMigrationFilter) ->when($search, function ($query, $search) { // Поиск по ФИО (точное совпадение или LIKE) return $query->where(function ($q) use ($search) { $q->where('full_name', 'ilike', "%{$search}%"); // PostgreSQL }); }) ->with([ 'latestMigration' => $periodMigrationFilter, 'migrations' => $departmentMigrationFilter, 'latestMigration.operations' => function ($q) use ($dateRange) { $q->where('start_date', '>=', $dateRange->startSql()) ->where('start_date', '<', $dateRange->endSql()); // по start_date }, 'latestMigration.reanimations', 'observable', 'operations' => function ($q) use ($departmentId, $dateRange) { $q->where('department_id', $departmentId) ->where('start_date', '>=', $dateRange->startSql()) ->where('start_date', '<', $dateRange->endSql()) // Только операции пока пациент реально лежал в отделении ->whereExists(function ($sub) use ($departmentId) { $sub->select(\DB::raw(1)) ->from('mv_migrationpatient_details') ->where('department_id', $departmentId) ->whereColumn('medical_history_id', 'mv_surgical_operations.medical_history_id') ->whereColumn('ingoing_date', '<=', 'mv_surgical_operations.start_date') ->where(function ($q2) { $q2->whereNull('out_date') ->orWhereColumn('out_date', '>=', 'mv_surgical_operations.start_date'); }); }); } ]); $all = $all ->selectRaw('DISTINCT ON (original_id) report_duty_patients.*') ->orderBy('original_id') ->orderBy('report_duty_id', 'desc') ->get(); //dd($all->where('original_id', 334564)->first()); // Добавляем вычисляемые поля и превращаем в плоский массив $prepared = $all->map(function (ReportDutyPatient $h) use ($dateRange) { $patientStatus = PatientStatusClassifier::classify($h, $dateRange); $periodFlags = PatientStatusClassifier::classifyPeriodFlags($h, $dateRange); $patientUrgency = null; $patientReanimation = null; if (!in_array($patientStatus, [ PatientStatusClassifier::STATUS_DECEASED, PatientStatusClassifier::STATUS_DISCHARGED, PatientStatusClassifier::STATUS_TRANSFERRED ])) { $patientUrgency = PatientStatusClassifier::classifyUrgency($h->urgency_id); $patientReanimation = PatientStatusClassifier::classifyReanimation($h->latestMigration?->reanimations, $dateRange); } return [ // Все исходные поля модели (автоматически через toArray) ...$h->toArray(), 'operations' => $h->operations, // + вычисляемые мета-поля для фронтенда 'patient_status' => $patientStatus, 'patient_urgency' => $patientUrgency, 'period_flags' => $periodFlags, 'in_reanimation' => $patientReanimation, 'admitted_today' => PatientStatusClassifier::classifyAdmitted($h->latestMigration?->ingoing_date, $dateRange), 'in_observable' => PatientStatusClassifier::classifyObservable($h->observable, $dateRange), ]; }); // 3. Сортировка $sortBy = 'recipient_date'; $sortOrder = 'desc'; $sorted = $prepared->sortBy($sortBy, SORT_REGULAR, $sortOrder === 'desc')->values(); // Операции $operations = $sorted->map(function ($h) { return $h['operations']; })->flatten(1); // 4. Возвращаем плоский массив + метаданные для фронтенда $countInDepartment = $sorted->where('period_flags.current_at_end', true)->count(); $countRecipient = $sorted->where('period_flags.recipient', true)->count(); $countDischarged = $sorted->where('period_flags.discharged', true)->count(); $countDeceased = $sorted->where('period_flags.deceased', true)->count(); $countUrgent = $sorted ->where('period_flags.current_at_end', true) ->where('period_flags.urgent', true) ->count(); $countPlanned = $sorted ->where('period_flags.current_at_end', true) ->where('period_flags.planned', true) ->count(); $countReanimations = $sorted->where('in_reanimation', true)->count(); $countSurgPlanned = $operations->where('urgent_status', 6)->count(); $countSurgUrgent = $operations->whereIn('urgent_status', [4, 5])->count(); // 4. Возвращаем плоский массив + метаданные для фронтенда return [ 'data' => $sorted->toArray(), 'meta' => [ 'total' => $sorted->count(), 'sortBy' => $sortBy, 'sortOrder' => $sortOrder, 'counts' => [ 'in_department' => $countInDepartment, 'recipient' => $countRecipient, 'discharged' => $countDischarged, 'deceased' => $countDeceased, 'urgent' => $countUrgent, 'planned' => $countPlanned, 'reanimations' => $countReanimations, 'surgical_planned' => $countSurgPlanned, 'surgical_urgent' => $countSurgUrgent, ] ] ]; } public function getHistories(DateRange $dateRange, int $departmentId) { $query = ReportDutyPatient::query(); $query->where('recipient_date', '>=', $dateRange->startSql()) ->where('recipient_date', '<', $dateRange->endSql()) // 1. Оставляем только тех пациентов, у которых БЫЛО движение в этом отделении ->whereHas('latestMigration', fn($q) => $q->where('department_id', $departmentId)) // 2. Загружаем ТОЛЬКО последнее движение в этом отделении (не все миграции) ->with(['latestMigration' => fn($q) => $q->where('department_id', $departmentId)]); $result = $query->paginate(); return $result; } public function getUrgencyHistory(DateRange $dateRange, int $departmentId, int $urgencyId) { $query = ReportDutyPatient::query(); $query->where('recipient_date', '>=', $dateRange->startSql()) ->where('recipient_date', '<', $dateRange->endSql()) ->urgency($urgencyId) ->whereHas('migrations', function ($m) use ($departmentId) { $m->where('department_id', $departmentId); }) ->with([ 'migrations' => fn ($m) => $m->where('department_id', $departmentId), 'migrations.operations' ]); $result = $query->paginate(); return $result; } public function getDepartmentHistories(DateRange $dateRange, int $departmentId) { return ReportDutyPatient::query() ->whereHas('migrations', function ($q) use ($departmentId, $dateRange) { $q->department($departmentId)->current($dateRange); }) ->with(['latestMigration' => function ($q) use ($departmentId, $dateRange) { $q->department($departmentId)->current($dateRange); // подгружаем только отфильтрованные движения }]) ->get() // Сортировка по дате поступления в отделение (поле дочерней таблицы) ->sortByDesc(fn ($mh) => $mh->latestMigration->ingoing_date ?? $mh->recipient_date) ->values(); } /** * Получить карты поступившие сегодня * @param DateRange $dateRange * @param int $departmentId */ public function getRecipientHistories(DateRange $dateRange, int $departmentId) { $now = Carbon::now(); return ReportDutyPatient::query() ->whereHas('migrations', function ($q) use ($departmentId, $dateRange) { $q->department($departmentId)->admitted($dateRange->startSql(), $dateRange->endSql()); }) ->with(['latestMigration' => function ($q) use ($departmentId) { $q->department($departmentId); }]) ->get(); } public function getDischargedHistories(DateRange $dateRange, int $departmentId) { return ReportDutyPatient::query() ->whereHas('migrations', function ($q) use ($departmentId, $dateRange) { $q->department($departmentId)->discharged($dateRange->startSql(), $dateRange->endSql()); }) ->with(['latestMigration' => function ($q) use ($departmentId) { $q->department($departmentId); }]) ->get(); } public function getDeceasedHistories(DateRange $dateRange, int $departmentId) { return ReportDutyPatient::query() ->whereHas('migrations', function ($q) use ($departmentId, $dateRange) { $q->department($departmentId)->deceased($dateRange->startSql(), $dateRange->endSql()); }) ->with(['latestMigration' => function ($q) use ($departmentId) { $q->department($departmentId); }]) ->get(); } public function getTransferredHistories(DateRange $dateRange, int $departmentId) { return ReportDutyPatient::query() ->whereHas('migrations', function ($q) use ($departmentId, $dateRange) { $q->department($departmentId)->transferred($dateRange->startSql(), $dateRange->endSql()); }) ->with(['latestMigration' => function ($q) use ($departmentId) { $q->department($departmentId); }]) ->get(); } }