Files
onboard/app/Services/DutyMedicalHistoryService.php
brusnitsyn 739168d427 Обновлен стартовый экран
Переписаны запросы для статистики, отчетов
Добавлена интеграция отчета сестры
2026-05-28 22:10:00 +09:00

274 lines
12 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<?php
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();
$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();
}
}