128 lines
4.9 KiB
PHP
128 lines
4.9 KiB
PHP
<?php
|
||
|
||
namespace App\Exports;
|
||
|
||
use App\Models\Department;
|
||
use App\Models\User;
|
||
use Illuminate\Support\Carbon;
|
||
use Illuminate\Support\Collection;
|
||
|
||
class DutyReportExport
|
||
{
|
||
public function __construct(
|
||
protected array $patients,
|
||
protected array $dateRange,
|
||
protected User $user,
|
||
protected Department $department,
|
||
protected string $reportName = 'Отчёт дежурного врача',
|
||
) {}
|
||
|
||
/**
|
||
* Данные для Blade-шаблона PDF-отчёта.
|
||
*/
|
||
public function toViewData(): array
|
||
{
|
||
$patients = collect($this->patients);
|
||
$startDate = Carbon::parse($this->dateRange[0]);
|
||
$endDate = Carbon::parse($this->dateRange[1]);
|
||
|
||
return [
|
||
'title' => sprintf('%s «%s»', $this->reportName, $this->department->name_full ?? $this->department->name_short),
|
||
'day' => $startDate->format('d'),
|
||
'month' => $startDate->locale('ru')->getTranslatedMonthName('Do MMMM'),
|
||
'year' => $endDate->format('Y'),
|
||
'planned' => $this->urgencyGroup($patients, 'planned'),
|
||
'urgent' => $this->urgencyGroup($patients, 'urgent'),
|
||
'inDepartment' => $patients->where('period_flags.current_at_end', true)->count(),
|
||
'plannedOperations' => $this->operationsGroup($patients, [6]),
|
||
'urgentOperations' => $this->operationsGroup($patients, [4, 5]),
|
||
'reanimation' => $this->flagGroup($patients, 'in_reanimation'),
|
||
'observables' => $this->observableGroup($patients),
|
||
'deceased' => $this->flagGroup($patients, 'period_flags.deceased'),
|
||
];
|
||
}
|
||
|
||
private function urgencyGroup(Collection $patients, string $flag): array
|
||
{
|
||
// Поступившие именно в этот отчётный период (сутки), а не все, кто вообще сейчас в отделении
|
||
$filtered = $patients
|
||
->where('period_flags.recipient', true)
|
||
->where("period_flags.{$flag}", true)
|
||
->values();
|
||
|
||
return [
|
||
'count' => $filtered->count(),
|
||
'patients' => $filtered->map(fn (array $p) => $this->presentPatient($p))->all(),
|
||
];
|
||
}
|
||
|
||
private function operationsGroup(Collection $patients, array $urgentStatuses): array
|
||
{
|
||
// latest_migration.operations уже ограничены периодом (start_date в рамках суток),
|
||
// в отличие от верхнеуровневого operations, у которого нижняя граница не задана
|
||
$filtered = $patients->filter(function (array $p) use ($urgentStatuses) {
|
||
return collect(data_get($p, 'latest_migration.operations', []))
|
||
->whereIn('urgent_status', $urgentStatuses)
|
||
->isNotEmpty();
|
||
})->values();
|
||
|
||
return [
|
||
'count' => $filtered->count(),
|
||
'patients' => $filtered->map(fn (array $p) => $this->presentPatient($p, withDiagnosis: false))->all(),
|
||
];
|
||
}
|
||
|
||
private function flagGroup(Collection $patients, string $flag): array
|
||
{
|
||
$filtered = $patients->where($flag, true)->values();
|
||
|
||
return [
|
||
'count' => $filtered->count(),
|
||
'patients' => $filtered->map(fn (array $p) => $this->presentPatient($p))->all(),
|
||
];
|
||
}
|
||
|
||
private function presentPatient(array $patient, bool $withDiagnosis = true): array
|
||
{
|
||
$age = ! empty($patient['birth_date'])
|
||
? (int) Carbon::parse($patient['birth_date'])->diffInYears(Carbon::parse($this->dateRange[1]))
|
||
: null;
|
||
|
||
return [
|
||
'full_name' => $patient['full_name'],
|
||
'age' => $age !== null ? "{$age} ".$this->pluralizeAge($age) : '',
|
||
'diagnosis' => $withDiagnosis ? (data_get($patient, 'latest_migration.diagnosis_name') ?? '') : null,
|
||
'migration_id' => (data_get($patient, 'latest_migration.original_id') ?? ''),
|
||
'observable_reason' => (data_get($patient, 'observable.observable_reason') ?? '')
|
||
];
|
||
}
|
||
|
||
private function observableGroup(Collection $patients): array
|
||
{
|
||
// Поступившие именно в этот отчётный период (сутки), а не все, кто вообще сейчас в отделении
|
||
$filtered = $patients
|
||
->where('in_observable', true)
|
||
->values();
|
||
|
||
return [
|
||
'count' => $filtered->count(),
|
||
'patients' => $filtered->map(fn (array $p) => $this->presentPatient($p))->all(),
|
||
];
|
||
}
|
||
private function pluralizeAge(int $age): string
|
||
{
|
||
$mod100 = $age % 100;
|
||
$mod10 = $age % 10;
|
||
|
||
if ($mod100 >= 11 && $mod100 <= 14) {
|
||
return 'лет';
|
||
}
|
||
|
||
return match ($mod10) {
|
||
1 => 'год',
|
||
2, 3, 4 => 'года',
|
||
default => 'лет',
|
||
};
|
||
}
|
||
}
|