346 lines
14 KiB
PHP
346 lines
14 KiB
PHP
<?php
|
||
|
||
namespace App\Http\Controllers\Web;
|
||
|
||
use App\Http\Controllers\Controller;
|
||
use App\Http\Resources\MedicalHistoryResource;
|
||
use App\Models\Department;
|
||
use App\Models\DepartmentMetrikaDefault;
|
||
use App\Models\ObservableMedicalHistory;
|
||
use App\Models\ReportDuty;
|
||
use App\Models\ReportNurse;
|
||
use App\Services\DateRangeService;
|
||
use App\Services\DutyMedicalHistoryService;
|
||
use App\Services\DutyReportService;
|
||
use App\Services\MedicalHistoryService;
|
||
use App\Services\NurseMedicalHistoryService;
|
||
use App\Services\NurseReportService;
|
||
use App\Services\UnifiedMedicalHistoryService;
|
||
use Illuminate\Http\Request;
|
||
use Illuminate\Support\Carbon;
|
||
use Illuminate\Support\Facades\Auth;
|
||
use Inertia\Inertia;
|
||
|
||
class DutyReportController extends Controller
|
||
{
|
||
public function __construct(
|
||
protected DateRangeService $dateRangeService,
|
||
protected MedicalHistoryService $medicalHistoryService,
|
||
protected DutyMedicalHistoryService $dutyMedicalHistoryService,
|
||
protected DutyReportService $dutyReportService,
|
||
protected NurseMedicalHistoryService $nurseMedicalHistoryService
|
||
)
|
||
{}
|
||
|
||
/**
|
||
* Получение базовой информации для заполнения отчета для дежурного
|
||
* @param Request $request
|
||
* @return \Inertia\Response
|
||
*/
|
||
public function index(Request $request)
|
||
{
|
||
$user = Auth::user();
|
||
$search = $request->get('search');
|
||
$selectedUserId = $request->query('userId') ? (int) $request->query('userId') : null;
|
||
$departmentId = $request->query('departmentId', $user->department->department_id);
|
||
$department = Department::where('department_id', $departmentId)->firstOrFail();
|
||
$bedsInDepartment = DepartmentMetrikaDefault::where('rf_department_id', $departmentId)
|
||
->where('rf_metrika_item_id', 1)->first()->value ?? 0;
|
||
$dateRange = $this->dateRangeService->getDateRangeFromRequest($request, $user);
|
||
|
||
$isRangeOneDay = $this->dateRangeService->isRangeOneDay($dateRange->startDate, $dateRange->endDate);
|
||
$isPastPeriod = $this->dateRangeService->isPastPeriod($dateRange);
|
||
$isCurrentPeriod = !$isPastPeriod;
|
||
|
||
// Всегда загружаем отчеты за период
|
||
$reportsDuty = ReportDuty::where('rf_department_id', $departmentId)
|
||
->where('period_start', '>=', $dateRange->startSql())
|
||
->where('period_end', '<=', $dateRange->endSql())
|
||
->orderBy('period_end', 'desc')
|
||
->with(['unwantedEvents', 'doctor'])
|
||
->get();
|
||
|
||
$reportsNurse = ReportNurse::where('rf_department_id', $departmentId)
|
||
->where('period_start', '>=', $dateRange->startSql())
|
||
->where('period_end', '<=', $dateRange->endSql())
|
||
->orderBy('period_end', 'desc')
|
||
->get();
|
||
|
||
$hasDutyReport = $reportsDuty->count() > 0;
|
||
$hasNurseReport = $reportsNurse->count() > 0;
|
||
|
||
$reportDutyIds = $reportsDuty->pluck('id')->toArray();
|
||
$reportNurseIds = $reportsNurse->pluck('id')->toArray();
|
||
|
||
// dd($reportsDuty, $dateRange->endSql());
|
||
|
||
// Получаем пациентов (источник зависит от периода)
|
||
if ($isCurrentPeriod) {
|
||
// Для текущего периода - пациенты из МИС
|
||
$patients = $this->medicalHistoryService->getGroupedHistories(
|
||
$dateRange,
|
||
$department->rf_mis_department_id,
|
||
$search
|
||
);
|
||
|
||
// Если есть отчет, загружаем из него дополнительные данные
|
||
if ($hasDutyReport) {
|
||
// Получаем нежелательные события и наблюдения из отчета
|
||
$reportData = $this->getReportAdditionalData($reportsDuty);
|
||
|
||
// Добавляем эти данные к пациентам
|
||
$patients = $this->mergeReportData($patients, $reportData);
|
||
}
|
||
|
||
$nursePatients = $hasNurseReport
|
||
? $this->nurseMedicalHistoryService->getGroupedHistories(
|
||
$dateRange,
|
||
$department->rf_mis_department_id,
|
||
$reportNurseIds
|
||
)
|
||
: [];
|
||
|
||
$currentPatients = $patients['meta']['counts']['in_department'];
|
||
$loaded = $bedsInDepartment > 0
|
||
? round(($currentPatients * 100) / $bedsInDepartment)
|
||
: 0;
|
||
|
||
$latestReport = $reportsDuty->first();
|
||
|
||
} else {
|
||
// Для прошедшего периода - данные из отчета
|
||
$patients = $hasDutyReport
|
||
? $this->dutyMedicalHistoryService->getGroupedHistories(
|
||
$dateRange,
|
||
$department->rf_mis_department_id,
|
||
$reportDutyIds,
|
||
$search
|
||
)
|
||
: $this->getEmptyPatientsData();
|
||
|
||
$nursePatients = $hasNurseReport
|
||
? $this->nurseMedicalHistoryService->getGroupedHistories(
|
||
$dateRange,
|
||
$department->rf_mis_department_id,
|
||
$reportNurseIds
|
||
)
|
||
: [];
|
||
|
||
$latestReport = $reportsDuty->first();
|
||
|
||
if ($latestReport && $hasDutyReport) {
|
||
$currentPatients = $patients['meta']['counts']['in_department'];
|
||
$loaded = $latestReport->getLoadedDepartmentAttribute($currentPatients);
|
||
} else {
|
||
$loaded = 0;
|
||
}
|
||
}
|
||
|
||
return Inertia::render('Report/Index', [
|
||
'department' => $department,
|
||
'patients' => $patients,
|
||
'nursePatients' => $nursePatients,
|
||
'latestReport' => $latestReport ?? null,
|
||
'canSaveReport' => $isRangeOneDay && $user->currentRoleCan('report.create'),
|
||
'canEditPastReport' => $user->currentRoleCan('report.edit.past'),
|
||
'canSaveNurseReport' => $isRangeOneDay && $user->currentRoleCan('nurse.report.create'),
|
||
'stats' => $this->prepareStats($patients, $nursePatients, $loaded, $bedsInDepartment),
|
||
'dates' => [
|
||
$dateRange->startDate->getTimestampMs(),
|
||
$dateRange->endDate->getTimestampMs(),
|
||
],
|
||
'selectedUserId' => $selectedUserId,
|
||
'selectedDepartmentId' => (int) $departmentId,
|
||
]);
|
||
}
|
||
|
||
/**
|
||
* Получает дополнительные данные из отчета (нежелательные события, наблюдения)
|
||
*/
|
||
private function getReportAdditionalData($reportsDuty): array
|
||
{
|
||
$unwantedEvents = [];
|
||
$observations = [];
|
||
|
||
foreach ($reportsDuty as $report) {
|
||
// Нежелательные события
|
||
foreach ($report->unwantedEvents as $event) {
|
||
$unwantedEvents[] = [
|
||
...$event->toArray(),
|
||
];
|
||
}
|
||
|
||
// Наблюдения (если есть связь)
|
||
if ($report->relationLoaded('observations') || $report->observations) {
|
||
foreach ($report->observations as $observation) {
|
||
$observations[] = [
|
||
...$observation->toArray(),
|
||
];
|
||
}
|
||
}
|
||
}
|
||
|
||
return [
|
||
'unwanted_events' => $unwantedEvents,
|
||
'observations' => $observations
|
||
];
|
||
}
|
||
|
||
/**
|
||
* Объединяет данные пациентов из МИС с данными из отчета
|
||
*/
|
||
private function mergeReportData(array $patients, array $reportData): array
|
||
{
|
||
// Группируем нежелательные события по отчетам
|
||
// $eventsByPatient = [];
|
||
// foreach ($reportData['unwanted_events'] as $event) {
|
||
// $reportId = $event['report_duty_id'];
|
||
// if (!isset($eventsByPatient[$reportId])) {
|
||
// $eventsByPatient[$reportId] = [];
|
||
// }
|
||
// $eventsByPatient[$reportId][] = $event;
|
||
// }
|
||
|
||
// Группируем наблюдения по пациентам
|
||
$observationsByPatient = [];
|
||
foreach ($reportData['observations'] as $observation) {
|
||
$patientId = $observation['patient_id'];
|
||
if (!isset($observationsByPatient[$patientId])) {
|
||
$observationsByPatient[$patientId] = [];
|
||
}
|
||
$observationsByPatient[$patientId][] = $observation;
|
||
}
|
||
|
||
// Добавляем данные из отчета к каждому пациенту
|
||
foreach ($patients['data'] as &$patient) {
|
||
$patientId = $patient['original_id'] ?? $patient['id'] ?? null;
|
||
|
||
// Может быть позже пригодится
|
||
// if ($patientId && isset($eventsByPatient[$patientId])) {
|
||
// $patient['unwanted_events'] = $eventsByPatient[$patientId];
|
||
// } else {
|
||
// $patient['unwanted_events'] = [];
|
||
// }
|
||
|
||
if ($patientId && isset($observationsByPatient[$patientId])) {
|
||
$patient['observations'] = $observationsByPatient[$patientId];
|
||
} else {
|
||
$patient['observations'] = [];
|
||
}
|
||
}
|
||
|
||
return $patients;
|
||
}
|
||
|
||
/**
|
||
* Получает данные из сестринского отчета
|
||
*/
|
||
private function getNurseReportAdditionalData($reportsNurse): array
|
||
{
|
||
$nurseData = [];
|
||
|
||
foreach ($reportsNurse as $report) {
|
||
// Загружаем необходимые данные из сестринского отчета
|
||
// Например, наблюдения медсестер, процедуры и т.д.
|
||
if ($report->relationLoaded('nurseObservations')) {
|
||
$nurseData = array_merge($nurseData, $report->nurseObservations->toArray());
|
||
}
|
||
}
|
||
|
||
return $nurseData;
|
||
}
|
||
|
||
/**
|
||
* Возвращает пустую структуру данных для пациентов
|
||
*/
|
||
private function getEmptyPatientsData(): array
|
||
{
|
||
return [
|
||
'data' => [],
|
||
'meta' => [
|
||
'total' => 0,
|
||
'sortBy' => 'ingoing_date',
|
||
'sortOrder' => 'desc',
|
||
'counts' => [
|
||
'in_department' => 0,
|
||
'recipient' => 0,
|
||
'discharged' => 0,
|
||
'deceased' => 0,
|
||
'urgent' => 0,
|
||
'planned' => 0,
|
||
'reanimations' => 0,
|
||
'surgical_planned' => 0,
|
||
'surgical_urgent' => 0,
|
||
]
|
||
]
|
||
];
|
||
}
|
||
|
||
/**
|
||
* Подготавливает статистику для отображения на фронтенде
|
||
*/
|
||
private function prepareStats(array $patients, array $nursePatients, int $loaded, ?int $bedsInDepartment): array
|
||
{
|
||
return [
|
||
'nurse' => [
|
||
'current' => empty($nursePatients) ? 0 : ($nursePatients['meta']['counts']['in_department'] ?? 0),
|
||
'recipient' => empty($nursePatients) ? 0 : ($nursePatients['meta']['counts']['recipient'] ?? 0),
|
||
'discharged' => empty($nursePatients) ? 0 : ($nursePatients['meta']['counts']['discharged'] ?? 0),
|
||
],
|
||
'duty' => [
|
||
'beds' => $bedsInDepartment ?? 0,
|
||
'loaded' => $loaded,
|
||
'current' => $patients['meta']['counts']['in_department'] ?? 0,
|
||
'recipient' => $patients['meta']['counts']['recipient'] ?? 0,
|
||
'discharged' => ($patients['meta']['counts']['discharged'] ?? 0) + ($patients['meta']['counts']['deceased'] ?? 0),
|
||
'deceased' => $patients['meta']['counts']['deceased'] ?? 0,
|
||
'surgical_planned' => $patients['meta']['counts']['surgical_planned'] ?? 0,
|
||
'surgical_urgent' => $patients['meta']['counts']['surgical_urgent'] ?? 0,
|
||
]
|
||
];
|
||
}
|
||
|
||
/**
|
||
* Сохранение отчета
|
||
* @return \Illuminate\Http\RedirectResponse
|
||
*/
|
||
public function store(Request $request)
|
||
{
|
||
abort_if(!auth()->user()->currentRoleCan('report.create'), 403);
|
||
|
||
$user = auth()->user();
|
||
$observables = $request->get('observables', []);
|
||
$unwantedEvents = $request->get('unwanted_events', []);
|
||
$selectedUserId = $request->get('userId') ? (int) $request->get('userId') : null;
|
||
$selectedDepartmentId = $request->get('departmentId') ? (int) $request->get('departmentId') : null;
|
||
$staff = (int) $request->get('staff', 0);
|
||
|
||
$dateRange = $this->dateRangeService->getDateRangeFromRequest($request, $user);
|
||
$report = $this->dutyReportService->saveReport($dateRange, null, $selectedUserId, $selectedDepartmentId);
|
||
$stats = $this->dutyReportService->saveSnapshot($dateRange, $report, null, auth()->id());
|
||
$this->dutyReportService->saveObservables($observables, $report);
|
||
$this->dutyReportService->saveUnwantedEvents($unwantedEvents, $report);
|
||
|
||
$this->dutyReportService->saveMetrics($stats, $report, $staff);
|
||
|
||
return redirect()->back();
|
||
}
|
||
|
||
public function closeObservation(Request $request)
|
||
{
|
||
$user = auth()->user();
|
||
$dateRange = $this->dateRangeService->getDateRangeFromRequest($request, $user);
|
||
|
||
$observable = $request->get('observable');
|
||
$observableId = $observable['id'] ?? null;
|
||
|
||
if ($observableId === null) return response()->json('Observable not found', 404);
|
||
|
||
$observable = ObservableMedicalHistory::find($observableId);
|
||
$observable->update([
|
||
'observable_out' => $dateRange->endDate,
|
||
'out_reason' => 'Закрыто пользователем'
|
||
]);
|
||
}
|
||
}
|