Обновлен стартовый экран

Переписаны запросы для статистики, отчетов
Добавлена интеграция отчета сестры
This commit is contained in:
brusnitsyn
2026-05-28 22:10:00 +09:00
parent 90e0d04dfd
commit 739168d427
96 changed files with 6663 additions and 1465 deletions

View File

@@ -9,35 +9,81 @@ use Illuminate\Support\Carbon;
class MedicalHistoryService
{
public function getGroupedHistories(DateRange $dateRange, int $departmentId): array
public function getGroupedHistories(DateRange $dateRange, int $departmentId, ?string $search = null): array
{
$startYear = Carbon::now()->startOfYear()->format('Y-m-d');
$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 = MedicalHistory::query()->whereHas('latestMigration', function ($q) use ($departmentId, $dateRange, $startYear) {
$q->where('department_id', $departmentId)
// пребывание пересекается с отчётным периодом
->where('ingoing_date', '<=', $dateRange->endSql())
->where('ingoing_date', '>=', $startYear)
->where(function ($sub) use ($dateRange) {
$sub->whereNull('out_date')
->orWhere('out_date', '>=', $dateRange->startSql())
->where('out_date', '<=', $dateRange->endSql());
});
})->with(['latestMigration' => function ($q) use ($departmentId) {
$q->where('department_id', $departmentId);
}, 'latestMigration.operations', 'latestMigration.reanimations'])->get();
$all = MedicalHistory::query()
->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');
});
});
}
])->get();
// 2. Добавляем вычисляемые поля и превращаем в плоский массив
$prepared = $all->map(function (MedicalHistory $h) use ($dateRange) {
$patientStatus = PatientStatusClassifier::classify($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);
])) {
$patientUrgency = PatientStatusClassifier::classifyUrgency($h->urgency_id);
$patientReanimation = PatientStatusClassifier::classifyReanimation($h->latestMigration?->reanimations, $dateRange);
}
return [
// Все исходные поля модели (автоматически через toArray)
...$h->toArray(),
@@ -45,7 +91,9 @@ class MedicalHistoryService
// + вычисляемые мета-поля для фронтенда
'patient_status' => $patientStatus,
'patient_urgency' => $patientUrgency,
'admitted_today' => PatientStatusClassifier::classifyAdmitted($h->latestMigration?->ingoing_date),
'in_reanimation' => $patientReanimation,
'admitted_today' => PatientStatusClassifier::classifyAdmitted($h->latestMigration?->ingoing_date, $dateRange),
'in_observable' => PatientStatusClassifier::classifyObservable($h->observable, $dateRange),
];
});
@@ -54,6 +102,21 @@ class MedicalHistoryService
$sortOrder = 'desc';
$sorted = $prepared->sortBy($sortBy, SORT_REGULAR, $sortOrder === 'desc')->values();
// Операции
$operations = $sorted->map(function ($h) {
return $h['operations'];
})->flatten(1);
$countInDepartment = $sorted->where('patient_status', 'in_department')->count();
$countRecipient = $sorted->where('patient_status', 'recipient')->count();
$countDischarged = $sorted->where('patient_status', 'discharged')->count();
$countDeceased = $sorted->where('patient_status', 'deceased')->count();
$countUrgent = $sorted->where('patient_urgency', 'urgent')->count();
$countPlanned = $sorted->where('patient_urgency', 'planned')->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(),
@@ -61,12 +124,16 @@ class MedicalHistoryService
'total' => $sorted->count(),
'sortBy' => $sortBy,
'sortOrder' => $sortOrder,
// Статистика для фильтров/бейджей (опционально)
'counts' => [
'in_department' => $sorted->where('patient_status', 'in_department')->count(),
'discharged' => $sorted->where('patient_status', 'discharged')->count(),
'urgent' => $sorted->where('patient_urgency', 'urgent')->count(),
'planned' => $sorted->where('patient_urgency', 'planned')->count(),
'in_department' => $countInDepartment + $countRecipient,
'recipient' => $countRecipient,
'discharged' => $countDischarged,
'deceased' => $countDeceased,
'urgent' => $countUrgent,
'planned' => $countPlanned,
'reanimations' => $countReanimations,
'surgical_planned' => $countSurgPlanned,
'surgical_urgent' => $countSurgUrgent,
]
]
];