start(); $periodEnd = $dateRange->end(); $periodStartCarbon = Carbon::parse($periodStart); $periodEndCarbon = Carbon::parse($periodEnd); $uniqueOperationIds = []; // Используем LazyCollection, чтобы не загружать всё в память foreach ($patients as $patient) { /** @var PatientSnapshotData $patient */ // ===== СТАТУСЫ ===== // Используем уже вычисленные поля (patientStatus, periodFlags и т.д.) // Но для расчёта койко-дней и операций нам нужны миграции и операции внутри периода. // Также мы можем переиспользовать логику, которая была в saveReportSnapshot. // Но мы перенесём сюда всю обработку, потому что здесь мы вычисляем статистики на основе сырых данных. $hasRecipientInPeriod = false; $hasTransferInPeriod = false; $hasDischargeInPeriod = false; $hasDeathInPeriod = false; $hasActiveMigrationInPeriod = false; $hasExtractInPeriod = false; // Проверяем extract_date из карты if ($patient->extractDate) { $extractDate = Carbon::parse($patient->extractDate); if ($extractDate >= $periodStartCarbon && $extractDate <= $periodEndCarbon) { $hasExtractInPeriod = true; } } // Идём по миграциям пациента (в массиве migrations) $migrations = $patient->migrations; // массив, но можно преобразовать в коллекцию $migrationOutDate = null; $migrationVisitResultId = null; foreach ($migrations as $migration) { $ingoingDate = isset($migration['ingoing_date']) ? Carbon::parse($migration['ingoing_date']) : null; $outDate = isset($migration['out_date']) ? Carbon::parse($migration['out_date']) : null; $visitResultId = $migration['visit_result_id'] ?? null; $statCureResultId = $migration['stat_cure_result_id'] ?? null; // Поступление в периоде if ($ingoingDate && $ingoingDate >= $periodStartCarbon && $ingoingDate <= $periodEndCarbon) { $hasRecipientInPeriod = true; } // Активная миграция на конец периода if ($ingoingDate && $ingoingDate <= $periodEndCarbon) { if (!$outDate || $outDate > $periodEndCarbon) { $hasActiveMigrationInPeriod = true; } } // Выбытие в периоде (есть out_date в периоде) if ($outDate && $outDate >= $periodStartCarbon && $outDate <= $periodEndCarbon) { $migrationOutDate = $outDate; $migrationVisitResultId = $visitResultId; if (in_array($visitResultId, [5, 15])) { $hasDeathInPeriod = true; } elseif (in_array($visitResultId, [4, 14])) { $hasTransferInPeriod = true; } else { $hasDischargeInPeriod = true; } } } // Если нет исхода по миграциям, проверяем extract_date и death_date if (!$hasDeathInPeriod && !$hasTransferInPeriod && !$hasDischargeInPeriod) { if ($hasExtractInPeriod) { $visitResultId = $patient->visitResultId; $deathDate = $patient->deathDate ? Carbon::parse($patient->deathDate) : null; if ($deathDate && $deathDate <= $periodEndCarbon) { $hasDeathInPeriod = true; } elseif (in_array($visitResultId, [4, 14])) { $hasTransferInPeriod = true; } else { $hasDischargeInPeriod = true; } } } // Заполнение статистики по статусам if ($hasDeathInPeriod) { $stats->deceased++; $stats->byStatus['deceased'] = ($stats->byStatus['deceased'] ?? 0) + 1; } elseif ($hasTransferInPeriod) { $stats->transferred++; $stats->byStatus['transferred'] = ($stats->byStatus['transferred'] ?? 0) + 1; } elseif ($hasDischargeInPeriod) { $stats->discharged++; $stats->outcome++; $stats->byStatus['discharged'] = ($stats->byStatus['discharged'] ?? 0) + 1; } elseif ($hasActiveMigrationInPeriod) { $stats->inDepartment++; $stats->byStatus['in_department'] = ($stats->byStatus['in_department'] ?? 0) + 1; } // Поступление (recipient) if ($hasRecipientInPeriod) { $stats->admitted['today']++; $stats->byStatus['recipient'] = ($stats->byStatus['recipient'] ?? 0) + 1; if ($patient->urgencyId == 1) { $stats->admitted['planned']++; $stats->planned++; } if ($patient->urgencyId == 2) { $stats->admitted['urgent']++; } } // Срочность (из patientUrgency, но можно из urgencyId) if ($patient->patientUrgency) { $stats->byUrgency[$patient->patientUrgency] = ($stats->byUrgency[$patient->patientUrgency] ?? 0) + 1; } // Реанимация if ($patient->inReanimation) { $stats->inReanimation++; } // Поступил сегодня (admittedToday) if ($patient->admittedToday) { $stats->admittedToday++; } // ===== КОЙКО-ДНИ И ОПЕРАЦИИ ===== // Нужно взять первую миграцию (актуальную) для расчёта койко-дней // берём первую миграцию из массива (индекс 0) if (!empty($migrations)) { $firstMigration = $migrations[0]; $migrationStart = isset($firstMigration['ingoing_date']) ? Carbon::parse($firstMigration['ingoing_date']) : null; $migrationEnd = isset($firstMigration['out_date']) ? Carbon::parse($firstMigration['out_date']) : null; if ($migrationStart) { // Проверяем пересечение с отчетным периодом $hasIntersection = $migrationStart <= $periodEndCarbon && ($migrationEnd === null || $migrationEnd >= $periodStartCarbon); if ($hasIntersection) { $calcStart = $migrationStart > $periodStartCarbon ? $migrationStart : $periodStartCarbon; $calcEnd = $migrationEnd && $migrationEnd < $periodEndCarbon ? $migrationEnd : $periodEndCarbon; $bedDays = $calcStart->diffInDays($calcEnd); $stats->totalBedDays += max(0, $bedDays); // Предоперационные дни: операции в периоде $opsInPeriod = collect($patient->operations ?? []) ->filter(function ($op) use ($periodStartCarbon, $periodEndCarbon) { $opStart = isset($op['start_date']) ? Carbon::parse($op['start_date']) : null; return $opStart && $opStart >= $periodStartCarbon && $opStart < $periodEndCarbon; }); if ($opsInPeriod->isNotEmpty()) { $stats->patientsWithOperations++; $firstOpInPeriod = $opsInPeriod->sortBy('start_date')->first(); if ($firstOpInPeriod && isset($firstOpInPeriod['start_date'])) { $opDate = Carbon::parse($firstOpInPeriod['start_date']); if ($opDate > $migrationStart) { $preOpDays = $migrationStart->copy()->startOfDay() ->diffInDays($opDate->copy()->startOfDay()); $stats->totalPreopBedDays += max(0, $preOpDays); } } } // Собираем операции для уникализации foreach ($patient->operations ?? [] as $operation) { $opStart = isset($operation['start_date']) ? Carbon::parse($operation['start_date']) : null; if ($opStart && $opStart >= $periodStartCarbon && $opStart < $periodEndCarbon) { $opId = $operation['id'] ?? null; if ($opId) { $uniqueOperationIds[$opId] = [ 'id' => $opId, 'urgent_status' => $operation['urgent_status'] ?? null, ]; } } } } } } // Увеличиваем общее количество пациентов (для среднего) $stats->totalPatients++; } // После цикла заполняем итоговые показатели по операциям $stats->totalOperations = count($uniqueOperationIds); $stats->plannedOperations = collect($uniqueOperationIds)->where('urgent_status', 6)->count(); $stats->urgentOperations = collect($uniqueOperationIds)->whereIn('urgent_status', [4,5])->count(); return $stats; } }