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

Переписаны запросы для статистики, отчетов
Добавлена интеграция отчета сестры
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

@@ -5,6 +5,8 @@ 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;
@@ -15,6 +17,7 @@ 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;
@@ -37,65 +40,306 @@ class DutyReportController extends Controller
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);
$existsReport = ReportDuty::where('rf_department_id', $departmentId)
->where('period_end', '>', $dateRange->startSql())
$isCurrentPeriod = !$isPastPeriod;
// Всегда загружаем отчеты за период
$reportsDuty = ReportDuty::where('rf_department_id', $departmentId)
->where('period_start', '>=', $dateRange->startSql())
->where('period_end', '<=', $dateRange->endSql())
->exists();
->orderBy('period_end', 'desc')
->with(['unwantedEvents', 'doctor'])
->get();
$hasReport = $existsReport && $isPastPeriod;
$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();
if ($hasReport) {
$inDepartmentHistories = $this->dutyMedicalHistoryService->getDepartmentHistories($dateRange, $department->rf_mis_department_id);
$plannedHistories = collect([ 'data' => [] ]);
$emergencyHistories = collect([ 'data' => [] ]);
$recipientHistories = $this->dutyMedicalHistoryService->getRecipientHistories($dateRange, $department->rf_mis_department_id);
$dischargedHistories = $this->dutyMedicalHistoryService->getDischargedHistories($dateRange, $department->rf_mis_department_id);
$deceasedHistories = $this->dutyMedicalHistoryService->getDeceasedHistories($dateRange, $department->rf_mis_department_id);
$transferredHistories = $this->dutyMedicalHistoryService->getTransferredHistories($dateRange, $department->rf_mis_department_id);
$reanimationHistories = collect([ 'data' => [] ]);
} else if ($this->dateRangeService->isPastPeriod($dateRange)) {
$inDepartmentHistories = collect([ 'data' => [] ]);
$plannedHistories = collect([ 'data' => [] ]);
$emergencyHistories = collect([ 'data' => [] ]);
$recipientHistories = collect([ 'data' => [] ]);
$dischargedHistories = collect([ 'data' => [] ]);
$deceasedHistories = collect([ 'data' => [] ]);
$transferredHistories = collect([ 'data' => [] ]);
$reanimationHistories = collect([ 'data' => [] ]);
} else {
$patients = $this->medicalHistoryService->getGroupedHistories($dateRange, $department->rf_mis_department_id);
// Для прошедшего периода - данные из отчета
$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,
'departmentInfo' => [
// TODO: Добавить вывод информации из шапки
],
'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);
$this->dutyReportService->saveSnapshot($dateRange, $report);
$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' => 'Закрыто пользователем'
]);
}
}