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

346 lines
14 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\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' => 'Закрыто пользователем'
]);
}
}