query('departmentId', $user->department->department_id); $department = Department::where('department_id', $departmentId)->firstOrFail(); $dateRange = $this->dateRangeService->getDateRangeFromRequest($request, $user); $statistics = $this->reportService->getReportStatistics($department, $user, $dateRange); $reportInfo = $this->reportService->getCurrentReportInfo($department, $user, $dateRange); $metrikaGroup = MetrikaGroup::whereMetrikaGroupId(2)->first(); $metrikaItems = $metrikaGroup->metrikaItems; return response()->json([ 'department' => [ 'department_id' => $department->department_id, 'department_name' => $department->name_full, 'beds' => $department->beds, ...$statistics, ], 'dates' => [ 'startAt' => $dateRange->startTimestamp(), 'endAt' => $dateRange->endTimestamp(), ], 'report' => $reportInfo, 'metrikaItems' => $metrikaItems, 'userId' => $reportInfo['userId'], 'userName' => $reportInfo['userName'], ]); } private function getSurgicalPatientsFromSnapshot(string $type, array $reportIds) { $count = 0; switch ($type) { case 'emergency': $count = $this->getMetrikaResult(10, $reportIds); break; case 'plan': $count = $this->getMetrikaResult(11, $reportIds); break; case 'recipient': $count = $this->getMetrikaResult(3, $reportIds); break; } return $count; } private function getPatientsCountFromSnapshot(string $type, array $reportIds) { $count = 0; switch ($type) { case 'emergency': $count = $this->getMetrikaResult(10, $reportIds); break; case 'plan': $count = $this->getMetrikaResult(11, $reportIds); break; case 'recipient': $count = $this->getMetrikaResult(3, $reportIds); break; case 'outcome': $count = $this->getMetrikaResult(7, $reportIds); break; case 'deceased': $count = $this->getMetrikaResult(9, $reportIds); break; case 'current': $count = $this->getMetrikaResult(8, $reportIds); break; } return $count; } private function getMetrikaResult(int $metrikaItemId, array $reportIds) { $reports = Report::whereIn('report_id', $reportIds) ->with('metrikaResults') ->get(); $count = 0; foreach ($reports as $report) { foreach ($report->metrikaResults as $metrikaResult) { if ($metrikaResult->rf_metrika_item_id === $metrikaItemId) { $count += intval($metrikaResult->value) ?? 0; } } } return $count; } /** * Получить ID поступивших пациентов из снапшотов */ private function getRecipientIdsFromSnapshots(array $reportIds) { $recipientIds = MedicalHistorySnapshot::whereIn('rf_report_id', $reportIds) ->where('patient_type', 'recipient') ->pluck('rf_medicalhistory_id') ->unique() ->toArray(); return $recipientIds; } public function store(Request $request) { $user = Auth::user(); $misDepartmentId = $user->department->rf_mis_department_id; $branchId = MisStationarBranch::where('rf_DepartmentID', $misDepartmentId) ->value('StationarBranchID'); // Определяем, является ли пользователь заведующим/администратором $isHeadOrAdmin = $user->isHeadOfDepartment() || $user->isAdmin(); $data = $request->validate([ 'metrics' => 'required', 'observationPatients' => 'nullable', 'departmentId' => 'required|integer', 'unwantedEvents' => 'nullable|array', 'startAt' => 'required|integer', 'endAt' => 'required|integer', 'userId' => 'required|integer', 'reportId' => 'nullable', ]); $metrics = $data['metrics']; $observationPatients = $data['observationPatients']; $unwantedEvents = $data['unwantedEvents']; // Определяем даты в зависимости от роли $dateRange = $this->dateRangeService->getDateRangeFromRequest($request, $user); $metriks = []; foreach ($metrics as $key => $value) { $metrika = new MetrikaResult; $metrikaId = (int) Str::replace('metrika_item_', '', $key); $metrika->rf_metrika_item_id = $metrikaId; $metrika->value = $value; $metriks[] = $metrika; } // 1. Плановые $planIds = $this->reportService->getPatientsByStatus( $user, 'plan', $dateRange, true, true, ); $planCount = $this->reportService->getPatientsCountByStatus($user, 'plan', $dateRange); // 2. Экстренные $emergencyIds = $this->reportService->getPatientsByStatus( $user, 'emergency', $dateRange, true, true, ); $emergencyCount = $this->reportService->getPatientsCountByStatus($user, 'emergency', $dateRange); // 3. Выписанные $dischargedIds = $this->reportService->getPatientsByStatus( $user, 'outcome', $dateRange, true, true ); // 4. Переведенные $transferredIds = $this->reportService->getPatientsByStatus( $user, 'outcome-transferred', $dateRange, true, true ); // 5. Умершие $deceasedIds = $this->reportService->getPatientsByStatus( $user, 'outcome-deceased', $dateRange, true, true ); // 6. Поступившие $recipientIds = $this->reportService->getPatientsByStatus( $user, 'recipient', $dateRange, true, true ); \DB::beginTransaction(); if (isset($data['reportId']) && $data['reportId']) { $report = Report::updateOrCreate( [ 'report_id' => $data['reportId'], ], [ 'rf_department_id' => $data['departmentId'], 'rf_user_id' => Auth::user()->id, 'rf_lpudoctor_id' => $data['userId'], 'created_at' => $dateRange->endSql(), 'sent_at' => $dateRange->endSql(), 'period_start' => $dateRange->startSql(), 'period_end' => $dateRange->endSql(), ] ); } else { $report = Report::create([ 'rf_department_id' => $data['departmentId'], 'rf_user_id' => Auth::user()->id, 'rf_lpudoctor_id' => $data['userId'], 'created_at' => $dateRange->endSql(), 'sent_at' => $dateRange->endSql(), 'period_start' => $dateRange->startSql(), 'period_end' => $dateRange->endSql(), ]); } if (count($unwantedEvents)) { foreach ($unwantedEvents as $unwantedEvent) { // Если есть ID - ищем по нему if (isset($unwantedEvent['unwanted_event_id']) && $unwantedEvent['unwanted_event_id']) { UnwantedEvent::updateOrCreate( ['unwanted_event_id' => $unwantedEvent['unwanted_event_id']], [ 'rf_report_id' => $report->report_id, 'comment' => $unwantedEvent['comment'] ?? '', 'title' => $unwantedEvent['title'] ?? '', 'is_visible' => $unwantedEvent['is_visible'] ?? true, ] ); } else { // Если нет ID - создаем новую запись UnwantedEvent::create([ 'rf_report_id' => $report->report_id, 'comment' => $unwantedEvent['comment'] ?? '', 'title' => $unwantedEvent['title'] ?? '', 'is_visible' => $unwantedEvent['is_visible'] ?? true, ]); } } } else { $unwantedEvents = $report->unwantedEvents; foreach ($unwantedEvents as $unwantedEvent) { $unwantedEvent->delete(); } } MetrikaResult::updateOrCreate( [ 'rf_report_id' => $report->report_id, 'rf_metrika_item_id' => 16, ], [ 'rf_report_id' => $report->report_id, 'rf_metrika_item_id' => 16, 'value' => count($unwantedEvents), ] ); foreach ($metriks as $metrika) { MetrikaResult::updateOrCreate( [ 'rf_report_id' => $report->report_id, 'rf_metrika_item_id' => $metrika->rf_metrika_item_id, ], [ 'rf_report_id' => $report->report_id, 'rf_metrika_item_id' => $metrika->rf_metrika_item_id, 'value' => $metrika->value, ] ); } if (count($observationPatients)) { foreach ($observationPatients as $observationPatient) { ObservationPatient::updateOrCreate( [ 'rf_medicalhistory_id' => $observationPatient['id'], 'rf_department_id' => $data['departmentId'], ], [ 'rf_department_id' => $data['departmentId'], 'rf_report_id' => $report->report_id, 'rf_medicalhistory_id' => $observationPatient['id'], 'rf_mkab_id' => null, 'comment' => $observationPatient['comment'] ?? null, ] ); } } else { foreach ($report->observationPatients as $observationPatient) { $observationPatient->delete(); } } MetrikaResult::updateOrCreate( [ 'rf_report_id' => $report->report_id, 'rf_metrika_item_id' => 14, ], [ 'rf_report_id' => $report->report_id, 'rf_metrika_item_id' => 14, 'value' => count($observationPatients), ] ); // Сохраняем снимок для каждого типа пациентов // Планово // $this->getPlanOrEmergencyPatients('plan', false, $branchId, $dateRange->startSql(), $dateRange->endSql(), false, false, true); foreach ($planIds as $id) { MedicalHistorySnapshot::create([ 'rf_report_id' => $report->report_id, 'rf_medicalhistory_id' => $id, 'patient_type' => 'plan', ]); } MetrikaResult::updateOrCreate( [ 'rf_report_id' => $report->report_id, 'rf_metrika_item_id' => 4, ], [ 'rf_report_id' => $report->report_id, 'rf_metrika_item_id' => 4, 'value' => $planCount, ] ); // $this->getPlanOrEmergencyPatients('emergency', false, $branchId, $startDate, $endDate, false, false, true); // Экстренно foreach ($emergencyIds as $id) { MedicalHistorySnapshot::create([ 'rf_report_id' => $report->report_id, 'rf_medicalhistory_id' => $id, 'patient_type' => 'emergency', ]); } MetrikaResult::updateOrCreate( [ 'rf_report_id' => $report->report_id, 'rf_metrika_item_id' => 12, ], [ 'rf_report_id' => $report->report_id, 'rf_metrika_item_id' => 12, 'value' => $emergencyCount, ] ); // $this->getDischargedPatients($branchId, $startDate, $endDate, true); foreach ($dischargedIds as $id) { MedicalHistorySnapshot::create([ 'rf_report_id' => $report->report_id, 'rf_medicalhistory_id' => $id, 'patient_type' => 'discharged', ]); } MetrikaResult::updateOrCreate( [ 'rf_report_id' => $report->report_id, 'rf_metrika_item_id' => 15, ], [ 'rf_report_id' => $report->report_id, 'rf_metrika_item_id' => 15, 'value' => count($dischargedIds), ] ); // $this->getTransferredPatients($branchId, $startDate, $endDate, true); foreach ($transferredIds as $id) { MedicalHistorySnapshot::create([ 'rf_report_id' => $report->report_id, 'rf_medicalhistory_id' => $id, 'patient_type' => 'transferred', ]); } MetrikaResult::updateOrCreate( [ 'rf_report_id' => $report->report_id, 'rf_metrika_item_id' => 13, ], [ 'rf_report_id' => $report->report_id, 'rf_metrika_item_id' => 13, 'value' => count($transferredIds), ] ); // $this->getDeceasedOutcomePatients($branchId, $startDate, $endDate, false, true); foreach ($deceasedIds as $id) { MedicalHistorySnapshot::create([ 'rf_report_id' => $report->report_id, 'rf_medicalhistory_id' => $id, 'patient_type' => 'deceased', ]); } MetrikaResult::updateOrCreate( [ 'rf_report_id' => $report->report_id, 'rf_metrika_item_id' => 9, ], [ 'rf_report_id' => $report->report_id, 'rf_metrika_item_id' => 9, 'value' => count($deceasedIds), ] ); // $recipientIds = $this->getPlanOrEmergencyPatients( // null, // $isHeadOrAdmin, // $branchId, // $startDate, // $endDate, // false, // true, // true, // today: true // ); foreach ($recipientIds as $id) { MedicalHistorySnapshot::create([ 'rf_report_id' => $report->report_id, 'rf_medicalhistory_id' => $id, 'patient_type' => 'recipient', ]); } MetrikaResult::updateOrCreate( [ 'rf_report_id' => $report->report_id, 'rf_metrika_item_id' => 3, ], [ 'rf_report_id' => $report->report_id, 'rf_metrika_item_id' => 3, 'value' => count($recipientIds), ] ); // 7. Находящиеся на лечении // $currentIds = $this->getCurrentPatients($branchId, false, true); // foreach ($currentIds as $id) { // MedicalHistorySnapshot::create([ // 'rf_report_id' => $report->report_id, // 'rf_medicalhistory_id' => $id, // 'patient_type' => 'current' // ]); // } \DB::commit(); return response()->json([ 'message' => 'success', ]); } public function getPatients(Request $request) { $user = Auth::user(); $validated = $request->validate([ 'status' => 'required|string', 'startAt' => 'nullable', 'endAt' => 'nullable', 'departmentId' => 'nullable', 'page' => 'nullable|integer|min:1', 'perPage' => 'nullable|integer|min:1|max:1000', 'search' => 'nullable|string|max:255', ]); $dateRange = $this->dateRangeService->getDateRangeFromRequest($request, $user); $departmentId = $request->get('departmentId', $user->department->department_id); $department = Department::where('department_id', $departmentId)->first(); $page = (int) ($validated['page'] ?? 1); $perPage = (int) ($validated['perPage'] ?? 20); $search = trim((string) ($validated['search'] ?? '')); $patients = collect($this->reportService->getPatientsByStatus( $department, Auth::user(), $validated['status'], $dateRange )); if ($this->resolveBaseStatus($validated['status']) === 'reanimation') { $this->attachReanimationIndicators($patients, (int) $department->department_id); } if ($search !== '') { $needle = mb_strtolower($search); $patients = $patients->filter(function ($patient) use ($needle) { $fullName = mb_strtolower(trim((string) ($patient->fullname ?? "{$patient->FAMILY} {$patient->Name} {$patient->OT}"))); $diagnosisCode = mb_strtolower((string) ($patient->mkb['ds'] ?? '')); $diagnosisName = mb_strtolower((string) ($patient->mkb['name'] ?? '')); return str_contains($fullName, $needle) || str_contains($diagnosisCode, $needle) || str_contains($diagnosisName, $needle); })->values(); } $total = $patients->count(); $items = $patients->forPage($page, $perPage)->values(); $data = FormattedPatientResource::collection($items)->resolve(); return response()->json([ 'data' => $data, 'meta' => [ 'total' => $total, 'page' => $page, 'perPage' => $perPage, 'lastPage' => max((int) ceil($total / max($perPage, 1)), 1), ], ]); } public function saveReanimationIndicator(Request $request) { $user = Auth::user(); $data = $request->validate([ 'departmentId' => 'nullable|integer', 'medical_history_id' => 'required|integer', 'indicator' => 'required|string|max:100', 'comment' => 'nullable|string|max:1000', 'startAt' => 'nullable', 'endAt' => 'nullable', ]); $departmentId = (int) ($data['departmentId'] ?? $user->department->department_id); $department = Department::where('department_id', $departmentId)->firstOrFail(); $dateRange = $this->dateRangeService->getDateRangeFromRequest($request, $user); $reportId = $this->getReportsForDateRange( $department->department_id, $dateRange->startSql(), $dateRange->endSql() )->pluck('report_id')->last(); $indicator = $this->reportService->saveReanimationIndicator( $user, $department->department_id, (int) $data['medical_history_id'], trim($data['indicator']), isset($data['comment']) ? trim((string) $data['comment']) : null, $reportId ? (int) $reportId : null ); return response()->json($indicator, 201); } public function getReanimationIndicatorHistory(Request $request) { $user = Auth::user(); $data = $request->validate([ 'departmentId' => 'nullable|integer', 'medical_history_id' => 'required|integer', 'limit' => 'nullable|integer|min:1|max:200', ]); $departmentId = (int) ($data['departmentId'] ?? $user->department->department_id); $history = $this->reportService->getReanimationIndicatorsHistory( $departmentId, (int) $data['medical_history_id'], (int) ($data['limit'] ?? 50) ); return response()->json($history); } public function getPatientsCount(Request $request) { $user = Auth::user(); $validated = $request->validate([ 'status' => 'required|string', 'startAt' => 'nullable', 'endAt' => 'nullable', 'departmentId' => 'nullable', ]); $dateRange = $this->dateRangeService->getDateRangeFromRequest($request, $user); $departmentId = $request->get('departmentId', $user->department->department_id); $department = Department::where('department_id', $departmentId)->first(); $count = $this->reportService->getPatientsCountByStatus( $department, $user, $validated['status'], $dateRange, ); return response()->json($count); } public function getPatientsCounts(Request $request) { $user = Auth::user(); $request->validate([ 'startAt' => 'nullable', 'endAt' => 'nullable', 'departmentId' => 'nullable', 'force' => 'nullable|boolean', ]); $dateRange = $this->dateRangeService->getDateRangeFromRequest($request, $user); $departmentId = $request->get('departmentId', $user->department->department_id); $department = Department::where('department_id', $departmentId)->firstOrFail(); $cacheKey = sprintf( 'report:patients-counts:%d:%d:%s:%s', $user->id, $department->department_id, $dateRange->startSql(), $dateRange->endSql() ); $force = (bool) $request->boolean('force', false); if ($force) { $counts = $this->reportService->getPatientsCountsMap($department, $user, $dateRange); Cache::put($cacheKey, $counts, now()->addSeconds(30)); } else { $counts = Cache::remember($cacheKey, now()->addSeconds(30), function () use ($department, $user, $dateRange) { return $this->reportService->getPatientsCountsMap($department, $user, $dateRange); }); } return response()->json([ 'counts' => $counts, ]); } /** * Получить пациентов (плановых или экстренных) */ private function getPlanOrEmergencyPatients( ?string $status, bool $isHeadOrAdmin, $branchId, $startDate, $endDate, bool $returnedCount = false, bool $all = false, bool $onlyIds = false, bool $today = false ) { // Определяем, является ли статус outcome $isOutcomeStatus = in_array($status, ['outcome-transferred', 'outcome-discharged', 'outcome-deceased']); if ($isOutcomeStatus) { $visitResultIds = match ($status) { 'outcome-transferred' => [4, 14], 'outcome-discharged' => [1, 11, 2, 12, 7, 18, 48], 'outcome-deceased' => [5, 6, 15, 16], default => [], }; $historyQuery = $this->buildOutcomeMedicalHistoryQuery( $branchId, $startDate, $endDate, $visitResultIds ); if ($onlyIds) { return $historyQuery->pluck('MedicalHistoryID')->values(); } if ($returnedCount) { return $historyQuery->count(); } return $historyQuery ->with(['surgicalOperations' => function ($query) use ($startDate, $endDate) { $query->where('Date', '>=', $startDate) ->where('Date', '<=', $endDate); }]) ->orderBy('DateRecipient', 'DESC') ->get(); } else { // Разная логика для заведующего и врача if ($isHeadOrAdmin) { // Заведующий: используем whereInDepartment $query = MisMigrationPatient::whereInDepartment($branchId) // ->whereBetween('DateIngoing', [$startDate, $endDate]); ->where('DateIngoing', '>=', $startDate) ->where('DateIngoing', '<=', $endDate); } else { // Врач: используем currentlyInTreatment + фильтр по дате $query = MisMigrationPatient::currentlyInTreatment($branchId) ->when($today, function ($query) use ($startDate, $endDate) { // return $query->whereBetween('DateIngoing', [$startDate, $endDate]); return $query->where('DateIngoing', '>=', $startDate) ->where('DateIngoing', '<=', $endDate); }); } } $medicalHistoryIds = $query->pluck('rf_MedicalHistoryID')->toArray(); if (empty($medicalHistoryIds)) { if ($returnedCount) { return 0; } return collect(); } // Получаем истории $query = MisMedicalHistory::whereIn('MedicalHistoryID', $medicalHistoryIds) ->with(['surgicalOperations' => function ($query) use ($startDate, $endDate) { // $query->whereBetween('Date', [$startDate, $endDate]); $query->where('Date', '>=', $startDate) ->where('Date', '<=', $endDate); }]) ->orderBy('DateRecipient', 'DESC'); // Выбираем план или экстренность if (! $all && ! $isOutcomeStatus) { if ($status === 'plan') { $query->plan(); } elseif ($status === 'emergency') { $query->emergency(); } } // Для врача добавляем условие "в отделении" if (! $isHeadOrAdmin && ! $isOutcomeStatus) { $query->currentlyHospitalized(); } if ($onlyIds) { return $query->select('MedicalHistoryID') ->pluck('MedicalHistoryID')->values(); } else { if ($returnedCount) { return $query->count(); } else { return $query->get(); } } } /** * Получить всех выбывших пациентов */ private function getAllOutcomePatients($branchId, $startDate, $endDate, bool $returnedCount = false) { $query = $this->buildOutcomeMedicalHistoryQuery($branchId, $startDate, $endDate); if ($returnedCount) { return $query->count(); } return $query ->with(['surgicalOperations']) ->orderBy('DateRecipient', 'DESC') ->get(); } /** * Получить понятное название типа выбытия */ private function getOutcomeTypeName($visitResultId): string { return match ($visitResultId) { 1, 7, 8, 9, 10, 11, 48, 49, 124 => 'Выписка', 2, 3, 4, 12, 13, 14 => 'Перевод', 5, 6, 15, 16 => 'Умер', // Добавьте другие коды по мере необходимости default => 'Другое ('.$visitResultId.')' }; } /** * Получить умерших пациентов (исход) */ private function getDeceasedOutcomePatients($branchId, $startDate, $endDate, bool $returnedCount = false, bool $onlyIds = false) { $query = $this->buildOutcomeMedicalHistoryQuery( $branchId, $startDate, $endDate, [5, 6, 15, 16] ); if ($onlyIds) { return $query->pluck('MedicalHistoryID')->values(); } if ($returnedCount) { return $query->count(); } else { return $query ->with(['surgicalOperations']) ->orderBy('DateRecipient', 'DESC') ->get(); } } private function buildOutcomeMedicalHistoryQuery( int $branchId, string $startDate, string $endDate, ?array $visitResultIds = null ) { $startDateOnly = Carbon::parse($startDate)->toDateString(); $endDateOnly = Carbon::parse($endDate)->toDateString(); return MisMedicalHistory::query() ->where('MedicalHistoryID', '<>', 0) ->whereDate('DateExtract', '>', $startDateOnly) ->whereDate('DateExtract', '<=', $endDateOnly) ->whereHas('migrations', function ($migrationQuery) use ($branchId, $visitResultIds) { $migrationQuery->where('rf_StationarBranchID', $branchId); if ($visitResultIds !== null && ! empty($visitResultIds)) { $migrationQuery->whereIn('rf_kl_VisitResultID', $visitResultIds); } }); } /** * Получить пациентов с операциями */ private function getSurgicalPatients(string $status, bool $isHeadOrAdmin, $branchId, $startDate, $endDate, bool $returnedCount = false) { $query = MisSurgicalOperation::where('rf_StationarBranchID', $branchId) ->completed() // ->whereBetween('Date', [$startDate, $endDate]) ->where('Date', '>=', $startDate) ->where('Date', '<=', $endDate) ->orderBy('Date', 'DESC'); if ($status === 'plan') { $query->where('rf_TypeSurgOperationInTimeID', 6); } else { $query->whereIn('rf_TypeSurgOperationInTimeID', [4, 5]); } if ($returnedCount) { return $query->count(); } else { return $query->get(); } } /** * Находятся на лечении */ private function getCurrentPatients($branchId, bool $returnedCount = false, bool $onlyIds = false) { // $currentCount = MisMedicalHistory::whereIn('MedicalHistoryID', $medicalHistoryIds) // ->currentlyHospitalized() // ->orderBy('DateRecipient', 'DESC') // ->count(); $medicalHistoryIds = MisMigrationPatient::currentlyInTreatment($branchId) ->pluck('rf_MedicalHistoryID') ->unique() ->toArray(); if (empty($medicalHistoryIds)) { if ($returnedCount) { return 0; } return collect(); } if ($onlyIds) { return $medicalHistoryIds; } $patients = MisMedicalHistory::whereIn('MedicalHistoryID', $medicalHistoryIds) ->currentlyHospitalized() ->with(['surgicalOperations']) ->orderBy('DateRecipient', 'DESC'); if ($returnedCount) { return $patients->count(); } else { return $patients->get(); } } public function removeObservation( Request $request, ) { $data = $request->validate([ 'id' => 'required|string', ]); $this->reportService->removeObservationPatient($data['id']); return response()->json()->setStatusCode(200); } public function createManualPatient(Request $request) { $user = Auth::user(); $data = $request->validate([ 'departmentId' => 'required|integer', 'report_id' => 'nullable|integer', 'startAt' => 'required_without:report_id', 'endAt' => 'required_without:report_id', 'user_id' => 'nullable|integer', 'full_name' => 'required|string|max:255', 'birth_date' => 'required|date', 'patient_kind' => 'required|in:plan,emergency', 'diagnosis_code' => 'nullable|string|max:255', 'diagnosis_name' => 'nullable|string|max:1000', 'admitted_at' => 'nullable|date', ]); $department = Department::where('department_id', $data['departmentId'])->firstOrFail(); $patient = $this->reportService->createManualPatient($department, $user, $data); return response()->json([ 'patient' => $patient, 'report_id' => $patient->rf_report_id, ], 201); } public function setManualPatientOutcome(Request $request, int $departmentPatientId) { $user = Auth::user(); $data = $request->validate([ 'outcome_type' => 'required|in:discharged,transferred,deceased', 'outcome_at' => 'nullable|date', ]); return response()->json( $this->reportService->setManualPatientOutcome($user, $departmentPatientId, $data) ); } public function updateManualPatient(Request $request, int $departmentPatientId) { $user = Auth::user(); $data = $request->validate([ 'full_name' => 'required|string|max:255', 'birth_date' => 'required|date', 'patient_kind' => 'required|in:plan,emergency', 'manual_status' => 'nullable|in:current,discharged,deceased', 'outcome_at' => 'nullable|date', 'diagnosis_code' => 'nullable|string|max:255', 'diagnosis_name' => 'nullable|string|max:1000', 'admitted_at' => 'nullable|date', 'startAt' => 'nullable', 'endAt' => 'nullable', ]); return response()->json( $this->reportService->updateManualPatient( $user, $departmentPatientId, $data ) ); } public function linkManualPatient(Request $request, int $departmentPatientId) { $data = $request->validate([ 'medical_history_id' => 'required|integer', ]); return response()->json( $this->reportService->linkManualPatientToMis($departmentPatientId, $data['medical_history_id']) ); } public function getManualPatientOperations(int $departmentPatientId) { $user = Auth::user(); $operations = $this->reportService->getManualPatientOperations($user, $departmentPatientId); return response()->json( DepartmentPatientOperationResource::collection($operations) ); } public function createManualPatientOperation(Request $request, int $departmentPatientId) { $user = Auth::user(); $data = $request->validate([ 'service_id' => 'required|integer', 'urgency' => 'required|in:plan,emergency', 'started_at' => 'required|date', 'ended_at' => 'required|date|after_or_equal:started_at', ]); $operation = $this->reportService->createManualPatientOperation($user, $departmentPatientId, $data); return response()->json(new DepartmentPatientOperationResource($operation), 201); } public function updateManualPatientOperation(Request $request, int $departmentPatientId, int $operationId) { $user = Auth::user(); $data = $request->validate([ 'service_id' => 'required|integer', 'urgency' => 'required|in:plan,emergency', 'started_at' => 'required|date', 'ended_at' => 'required|date|after_or_equal:started_at', ]); $operation = $this->reportService->updateManualPatientOperation($user, $departmentPatientId, $operationId, $data); return response()->json(new DepartmentPatientOperationResource($operation)); } public function deleteManualPatientOperation(int $departmentPatientId, int $operationId) { $user = Auth::user(); $this->reportService->deleteManualPatientOperation($user, $departmentPatientId, $operationId); return response()->json()->setStatusCode(204); } public function searchMisPatients(Request $request) { $data = $request->validate([ 'departmentId' => 'required|integer', 'query' => 'required|string|min:2', ]); $department = Department::where('department_id', $data['departmentId'])->firstOrFail(); $patients = $this->reportService->searchMisPatientsForDepartment($department, $data['query']); return response()->json(FormattedPatientResource::collection($patients)); } public function searchMkb(Request $request) { $data = $request->validate([ 'query' => 'required|string|min:1|max:255', ]); $query = trim($data['query']); $needle = mb_strtolower($query, 'UTF-8'); $like = "%{$needle}%"; $items = MisMKB::query() ->select(['MKBID', 'DS', 'NAME']) ->where(function ($builder) use ($like) { $builder->whereRaw('LOWER("DS") LIKE ?', [$like]) ->orWhereRaw('LOWER("NAME") LIKE ?', [$like]); }) ->orderBy('DS') ->limit(30) ->get() ->map(fn (MisMKB $item) => [ 'id' => $item->MKBID, 'code' => $item->DS, 'name' => $item->NAME, 'label' => trim(($item->DS ? "{$item->DS} " : '').($item->NAME ?? '')), ]) ->values(); return response()->json($items); } public function searchMedicalServices(Request $request) { $data = $request->validate([ 'query' => 'required|string|min:2|max:255', ]); $query = trim($data['query']); $items = \App\Models\MisServiceMedical::query() ->select(['ServiceMedicalID', 'ServiceMedicalCode', 'ServiceMedicalName']) ->where(function ($builder) use ($query) { $builder->where('ServiceMedicalCode', 'like', "%{$query}%") ->orWhere('ServiceMedicalName', 'like', "%{$query}%"); }) ->orderBy('ServiceMedicalCode') ->limit(30) ->get() ->map(fn (\App\Models\MisServiceMedical $item) => [ 'id' => $item->ServiceMedicalID, 'code' => $item->ServiceMedicalCode, 'name' => $item->ServiceMedicalName, 'label' => trim(($item->ServiceMedicalCode ? "{$item->ServiceMedicalCode} " : '').($item->ServiceMedicalName ?? '')), ]) ->values(); return response()->json($items); } // api/report/unwanted-event public function removeUnwantedEvent(UnwantedEvent $unwantedEvent, Request $request) { $unwantedEvent->delete(); return response()->json()->setStatusCode(200); } public function getDepartmentUsers(Request $request) { $user = Auth::user(); $departmentId = $user->department->rf_mis_department_id; $users = MisLpuDoctor::select(['LPUDoctorID', 'FAM_V', 'IM_V', 'OT_V']) ->whereHas('prvds', function ($query) use ($departmentId) { $query->where('rf_DepartmentID', $departmentId) ->whereDate('D_END', '2222-01-01 00:00:00.000000'); }) ->active() ->whereNotIn('LPUDoctorID', [0, 1]) ->orderBy('FAM_V') ->get(); return response()->json([ ...$users, ])->setStatusCode(200); } /** * Получить все отчеты в промежутке дат (для агрегации данных) */ private function getReportsForDateRange($departmentId, $startDate, $endDate) { if (Carbon::parse($startDate)->diffInDays(Carbon::parse($endDate)) > 1.0) { return Report::where('rf_department_id', $departmentId) ->withinPeriod($startDate, $endDate) ->orderBy('period_end', 'ASC') ->get(); } else { return Report::where('rf_department_id', $departmentId) ->exactPeriod($startDate, $endDate) ->orderBy('period_end', 'ASC') ->get(); } } private function resolveBaseStatus(string $status): string { if (str_starts_with($status, 'mis-')) { return substr($status, 4); } if (str_starts_with($status, 'special-')) { return substr($status, 8); } return $status; } private function attachReanimationIndicators(Collection $patients, int $departmentId): void { if ($patients->isEmpty()) { return; } $medicalHistoryIds = $patients ->map(function ($patient) { return (int) ($patient->medicalHistoryId ?? $patient->MedicalHistoryID ?? 0); }) ->filter() ->unique() ->values() ->all(); if (empty($medicalHistoryIds)) { return; } $latestIndicators = $this->reportService->getLatestReanimationIndicators($departmentId, $medicalHistoryIds); $patients->transform(function ($patient) use ($latestIndicators) { $medicalHistoryId = (int) ($patient->medicalHistoryId ?? $patient->MedicalHistoryID ?? 0); $indicator = $medicalHistoryId ? $latestIndicators->get($medicalHistoryId) : null; $patient->reanimation_indicator = $indicator?->indicator; $patient->reanimation_comment = $indicator?->comment; return $patient; }); } public function checkReport(Request $request) { $request->validate([ 'department_id' => 'required|integer|exists:departments,department_id', ]); $report = Report::where('rf_department_id', $request->department_id) ->exactPeriod(now('Asia/Yakutsk')->subDay()->setTime(7, 0)->format('Y-m-d H:i:s'), now('Asia/Yakutsk')->setTime(7, 0)->format('Y-m-d H:i:s')) ->first(); return response()->json([ 'report_id' => $report?->report_id, 'exists' => (bool) $report, ]); } }