Обновлен стартовый экран
Переписаны запросы для статистики, отчетов Добавлена интеграция отчета сестры
This commit is contained in:
@@ -3,10 +3,167 @@
|
||||
namespace App\Services;
|
||||
|
||||
use App\Models\ReportDutyPatient;
|
||||
use App\Services\Classification\PatientStatusClassifier;
|
||||
use Illuminate\Support\Carbon;
|
||||
|
||||
class DutyMedicalHistoryService
|
||||
{
|
||||
public function getGroupedHistories(
|
||||
DateRange $dateRange,
|
||||
int $departmentId,
|
||||
?array $reportIds = null,
|
||||
?string $search = null
|
||||
): array
|
||||
{
|
||||
$startYear = $dateRange->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();
|
||||
|
||||
Reference in New Issue
Block a user