department; $startDateCarbon = Carbon::now()->firstOfMonth(); $endDateCarbon = Carbon::now(); // Определяем даты в зависимости от роли [$startDate, $endDate] = $this->getDateRangeForRole($user, $request->query('startAt'), $request->query('endAt')); if (Carbon::parse($startDate)->isValid()) { $startDateCarbon = Carbon::parse($startDate)->setTimeZone('Asia/Yakutsk'); } if (Carbon::parse($endDate)->isValid()) { $endDateCarbon = Carbon::parse($endDate)->setTimeZone('Asia/Yakutsk'); } $beds = (int)$department->metrikaDefault()->where('rf_metrika_item_id', 1)->first()->value; $occupiedBeds = optional(Report::where('rf_department_id', $user->rf_department_id) ->join('metrika_results', 'reports.report_id', '=', 'metrika_results.rf_report_id') ->where('metrika_results.rf_metrika_item_id', 8) ->orderBy('sent_at', 'desc')->first())->value ?? 0; $percentLoadedBeds = round(intval($occupiedBeds) * 100 / $beds); //intval($occupiedBeds) * 100 / $beds; $metrikaGroup = MetrikaGroup::whereMetrikaGroupId(2)->first(); $metrikaItems = $metrikaGroup->metrikaItems; $misDepartmentId = $request->user()->department->rf_mis_department_id; $branchId = MisStationarBranch::where('rf_DepartmentID', $misDepartmentId) ->value('StationarBranchID'); $unwantedEvents = UnwantedEvent::whereHas('report', function ($query) use ($user, $startDate, $endDate) { $query->where('rf_department_id', $user->rf_department_id) ->whereBetween('created_at', [$startDate, $endDate]); }) ->get()->map(function ($item) { return [ ...$item->toArray(), 'created_at' => Carbon::parse($item->created_at)->format('Создано d.m.Y в H:i'), ]; }); // Определяем, является ли пользователь заведующим/администратором $isHeadOrAdmin = $user->isHeadOfDepartment() || $user->isAdmin(); $plan = $this->getPlanOrEmergencyPatients( 'plan', $isHeadOrAdmin, $branchId, $startDate, $endDate, true, today: true ); $emergency = $this->getPlanOrEmergencyPatients( 'emergency', $isHeadOrAdmin, $branchId, $startDate, $endDate, true, today: true ); $outcomeCount = $this->getAllOutcomePatients( $branchId, $startDate, $endDate, true ); $currentCount = $this->getCurrentPatients($branchId, true); $recipientIds = $this->getPlanOrEmergencyPatients( null, $isHeadOrAdmin, $branchId, $startDate, $endDate, false, true, true, today: true ); return response()->json([ 'department' => [ 'beds' => $beds, 'percentLoadedBeds' => $percentLoadedBeds, 'recipientCount' => $plan + $emergency, //$recipientCount, 'extractCount' => $outcomeCount, //$extractedCount, 'currentCount' => $currentCount, 'deadCount' => $this->getDeceasedOutcomePatients($branchId, $startDate, $endDate, true), 'surgicalCount' => [ $this->getSurgicalPatients('plan', $isHeadOrAdmin, $branchId, $startDate, $endDate, true), $this->getSurgicalPatients('emergency', $isHeadOrAdmin, $branchId, $startDate, $endDate, true) ], 'recipientIds' => $recipientIds, ], 'dates' => [ 'startAt' => $startDateCarbon->getTimestampMs(), 'endAt' => $endDateCarbon->getTimestampMs() ], 'report' => [ 'unwantedEvents' => $unwantedEvents, 'isActiveSendButton' => Carbon::createFromFormat('Y-m-d H:i:s', $endDate)->isToday() && (!$user->isHeadOfDepartment() && !$user->isAdmin()), ], 'metrikaItems' => $metrikaItems ]); } 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', 'dates' => 'required|array', ]); $metrics = $data['metrics']; $observationPatients = $data['observationPatients']; $unwantedEvents = $data['unwantedEvents']; // Определяем даты в зависимости от роли [$startDate, $endDate] = $this->getDateRangeForRole($user, $data['dates'][0], $data['dates'][1]); $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; } \DB::beginTransaction(); $report = Report::create([ 'rf_department_id' => $data['departmentId'], 'rf_user_id' => Auth::user()->id, 'created_at' => now(), 'sent_at' => now() ]); 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, ]); } } } foreach ($metriks as $metrika) { $metrika->rf_report_id = $report->report_id; $metrika->save(); } foreach ($observationPatients as $observationPatient) { ObservationPatient::create([ 'rf_department_id' => $data['departmentId'], 'rf_report_id' => $report->report_id, 'rf_medicalhistory_id' => $observationPatient['id'], 'rf_mkab_id' => null, 'comment' => $observationPatient['comment'] ?? null ]); } // Сохраняем снимок для каждого типа пациентов // 1. Плановые $planIds = $this->getPlanOrEmergencyPatients('plan', false, $branchId, $startDate, $endDate, false, false, true); foreach ($planIds as $id) { MedicalHistorySnapshot::create([ 'rf_report_id' => $report->report_id, 'rf_medicalhistory_id' => $id, 'patient_type' => 'plan' ]); } // 2. Экстренные $emergencyIds = $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' ]); } // 3. Выписанные $dischargedIds = $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' ]); } // 4. Переведенные $transferredIds = $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' ]); } // 5. Умершие $deceasedIds = $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' ]); } // 6. Находящиеся на лечении // $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(); $data = $request->validate([ 'status' => 'required|string', // plan emergency observation deceased 'startAt' => 'nullable', 'endAt' => 'nullable', ]); // Получаем базовые данные $status = $data['status']; $model = new MisMedicalHistory(); $misDepartmentId = $request->user()->department->rf_mis_department_id; $userDepartmentId = $request->user()->department->department_id; $branchId = MisStationarBranch::where('rf_DepartmentID', $misDepartmentId)->value('StationarBranchID'); if (!$branchId) { return response()->json([]); } // Определяем даты в зависимости от роли [$startDate, $endDate] = $this->getDateRangeForRole($user, $data['startAt'] ?? null, $data['endAt'] ?? null); // dd($startDate, $endDate); // Определяем, является ли пользователь заведующим/администратором $isHeadOrAdmin = $user->isHeadOfDepartment() || $user->isAdmin(); // Обработка каждого статуса $patients = match($status) { 'plan', 'emergency' => $this->getPlanOrEmergencyPatients($status, $isHeadOrAdmin, $branchId, $startDate, $endDate), 'observation' => $this->getObservationPatients($userDepartmentId), 'outcome-discharged' => $this->getDischargedPatients($branchId, $startDate, $endDate), 'outcome-transferred' => $this->getTransferredPatients($branchId, $startDate, $endDate), 'outcome-deceased' => $this->getDeceasedOutcomePatients($branchId, $startDate, $endDate), default => 0 }; // dd($patients->pluck('MedicalHistoryID')->toArray()); // Если есть пациенты, добавляем дополнительные данные if ($patients->isNotEmpty()) { $patients = $patients->map(function ($item, $index) use ($branchId, $startDate, $endDate) { $item->num = $index + 1; $item->misStationarBranchId = $branchId; $item->startDate = $startDate; $item->endDate = $endDate; return $item; }); // Загружаем связи $patients->load(['migrations' => function ($query) use ($startDate, $endDate, $branchId) { $query->whereHas('diagnosis', function ($q) { $q->where('rf_DiagnosTypeID', 3); }) ->with('diagnosis.mkb') ->where('rf_StationarBranchID', $branchId); }]); } return response()->json(FormattedPatientResource::collection($patients)); } public function getPatientsCount(Request $request) { $user = Auth::user(); $data = $request->validate([ 'status' => 'required|string', // plan emergency observation deceased 'startAt' => 'nullable', 'endAt' => 'nullable', ]); // Получаем базовые данные $status = $data['status']; $model = new MisMedicalHistory(); $misDepartmentId = $request->user()->department->rf_mis_department_id; $userDepartmentId = $request->user()->department->department_id; $branchId = MisStationarBranch::where('rf_DepartmentID', $misDepartmentId)->value('StationarBranchID'); if (!$branchId) { return response()->json([]); } // Определяем даты в зависимости от роли [$startDate, $endDate] = $this->getDateRangeForRole($user, $data['startAt'] ?? null, $data['endAt'] ?? null); // Определяем, является ли пользователь заведующим/администратором $isHeadOrAdmin = $user->isHeadOfDepartment() || $user->isAdmin(); $isOutcomeOrObservation = in_array($status, ['outcome', 'observation']); if ($isOutcomeOrObservation) { switch ($status) { case 'observation': $count = ObservationPatient::where('rf_department_id', $userDepartmentId)->count(); break; case 'outcome': $count = $this->getAllOutcomePatients($branchId, $startDate, $endDate, true); break; } } else { $count = $this->getPlanOrEmergencyPatients($status, $isHeadOrAdmin, $branchId, $startDate, $endDate, true); } return response()->json($count); } public function getRecipientIds(bool $isHeadOrAdmin, $branchId, $startDate, $endDate) { } /** * Определить диапазон дат в зависимости от роли */ private function getDateRangeForRole($user, $startAt = null, $endAt = null): array { // Функция для парсинга даты $parseDate = function($dateInput) { if (is_numeric($dateInput)) { return Carbon::createFromTimestampMs($dateInput) ->setTimezone('Asia/Yakutsk'); } return Carbon::parse($dateInput, 'Asia/Yakutsk'); }; // Если переданы обе даты (и заведующий, и врач могут выбрать даты) if ($startAt && $endAt) { $startDate = $parseDate($startAt); $endDate = $parseDate($endAt); // Если пользователь врач - всегда применяем правило "-1 день" // if (!$user->isHeadOfDepartment() && !$user->isAdmin()) { // // Для врача: endDate - выбранная дата, startDate - выбранная дата -1 день // $startDate = $endDate->copy()->subDay(); // } // Если даты одинаковые (выбран один день) или врач // dd($startDate->isSameDay($endDate) || (!$user->isHeadOfDepartment() && !$user->isAdmin()))0 // dd($startDate->isCurrentDay()); if ($startDate->isSameDay($endDate)) { // Сдвигаем начало на день назад для всех ролей при выборе одного дня // И всегда для врача $startDate = $startDate->copy()->addDays(-1)->setTime(6, 0)->format('Y-m-d H:i:s'); $endDate = $endDate->setTime(6, 0)->format('Y-m-d H:i:s'); } else { // Для диапазона оставляем как есть (только для заведующих) $startDate = $startDate->setTime(6, 0)->format('Y-m-d H:i:s'); $endDate = $endDate->setTime(6, 0)->format('Y-m-d H:i:s'); } // dd($startDate); // dd($startDate, $endDate); } // Если даты не переданы - логика по умолчанию в зависимости от роли else { // Для заведующего или администратора - период месяца if ($user->isHeadOfDepartment() || $user->isAdmin()) { $startDate = Carbon::now('Asia/Yakutsk') ->firstOfMonth() ->setTime(6, 0) ->format('Y-m-d H:i:s'); $endDate = Carbon::now('Asia/Yakutsk') ->setTime(6, 0) ->format('Y-m-d H:i:s'); } // Для врача - только сутки (вчера 06:00 - сегодня 06:00) else { $startDate = Carbon::now('Asia/Yakutsk')->subDay()->setTime(6, 0)->format('Y-m-d H:i:s'); $endDate = Carbon::now('Asia/Yakutsk')->setTime(6, 0)->format('Y-m-d H:i:s'); } } return [$startDate, $endDate]; } /** * Получить пациентов (плановых или экстренных) */ 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) { switch ($status) { case 'outcome-transferred': $query = MisMigrationPatient::transferred($branchId, $startDate, $endDate); break; case 'outcome-discharged': $query = MisMigrationPatient::discharged($branchId, $startDate, $endDate); break; case 'outcome-deceased': $query = MisMigrationPatient::deceasedOutcome($branchId, $startDate, $endDate); break; } } else { // Разная логика для заведующего и врача if ($isHeadOrAdmin) { // Заведующий: используем whereInDepartment $query = MisMigrationPatient::whereInDepartment($branchId) ->whereBetween('DateIngoing', [$startDate, $endDate]); } else { // Врач: используем currentlyInTreatment + фильтр по дате $query = MisMigrationPatient::currentlyInTreatment($branchId) ->when($today, function ($query) use ($startDate, $endDate) { return $query->whereBetween('DateIngoing', [$startDate, $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]); }]) ->orderBy('DateRecipient', 'DESC'); // Выбираем план или экстренность if (!$all && !$isOutcomeStatus) { if ($status === 'plan') { $query->plan(); } else if ($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 getObservationPatients( $userDepartmentId ) { $observationPatients = ObservationPatient::where('rf_department_id', $userDepartmentId) ->select(['rf_medicalhistory_id', 'observation_patient_id']) ->get() ->groupBy('rf_medicalhistory_id'); $medicalHistoryIds = $observationPatients->keys()->toArray(); if (empty($medicalHistoryIds)) { return collect(); } $patients = MisMedicalHistory::whereHas('observationPatient', function ($q) use ($userDepartmentId) { $q->where('rf_department_id', $userDepartmentId); }) ->with(['observationPatient' => function($query) use ($userDepartmentId) { $query->where('rf_department_id', $userDepartmentId) ->select(['rf_medicalhistory_id', 'observation_patient_id', 'comment']); }]) ->orderBy('DateRecipient', 'DESC') ->get(); // Добавляем комментарии $patients = $patients->map(function ($patient) { // Объединяем все комментарии $patient->comment = $patient->observationPatient ->pluck('comment') ->filter() ->implode('; '); return $patient; }); return $patients; } /** * Получить выбывших пациентов */ private function getOutcomePatients( $misDepartmentId, $startDate, $endDate ) { // Здесь оставляем оригинальный запрос, т.к. он специфичен для умерших return MisMedicalHistory::deceased() ->inDepartment($misDepartmentId, $startDate, $endDate) ->get(); } /** * Получить всех выбывших пациентов */ private function getAllOutcomePatients($branchId, $startDate, $endDate, bool $returnedCount = false) { // Сначала получаем миграции с типами выбытия $migrations = MisMigrationPatient::outcomePatients($branchId, $startDate, $endDate) ->select('rf_MedicalHistoryID', 'rf_kl_VisitResultID', 'DateOut') ->get() ->groupBy('rf_MedicalHistoryID'); if ($migrations->isEmpty()) { if ($returnedCount) return 0; return collect(); } $medicalHistoryIds = $migrations->keys()->toArray(); // Получаем истории $patients = MisMedicalHistory::whereIn('MedicalHistoryID', $medicalHistoryIds) ->with(['surgicalOperations']) ->orderBy('DateRecipient', 'DESC'); if ($returnedCount) return $patients->count(); else $patients = $patients->get(); // Добавляем информацию о типе выбытия return $patients->map(function ($patient) use ($migrations) { $patientMigrations = $migrations->get($patient->MedicalHistoryID, collect()); // Определяем основной тип выбытия (берем последнюю миграцию) $latestMigration = $patientMigrations->sortByDesc('DateOut')->first(); if ($latestMigration) { $patient->outcome_type = $this->getOutcomeTypeName($latestMigration->rf_kl_VisitResultID); $patient->outcome_date = $latestMigration->DateOut; $patient->visit_result_id = $latestMigration->rf_kl_VisitResultID; } return $patient; }); } /** * Получить понятное название типа выбытия */ 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 getDischargedPatients($branchId, $startDate, $endDate, bool $onlyIds = false) { $medicalHistoryIds = MisMigrationPatient::discharged($branchId, $startDate, $endDate) ->pluck('rf_MedicalHistoryID') ->unique() ->toArray(); if (empty($medicalHistoryIds)) { return collect(); } if ($onlyIds) { return $medicalHistoryIds; } return MisMedicalHistory::whereIn('MedicalHistoryID', $medicalHistoryIds) ->with(['surgicalOperations']) ->orderBy('DateRecipient', 'DESC') ->get(); } /** * Получить переведенных пациентов */ private function getTransferredPatients($branchId, $startDate, $endDate, bool $onlyIds = false) { $medicalHistoryIds = MisMigrationPatient::transferred($branchId, $startDate, $endDate) ->pluck('rf_MedicalHistoryID') ->unique() ->toArray(); if (empty($medicalHistoryIds)) { return collect(); } if ($onlyIds) { return $medicalHistoryIds; } return MisMedicalHistory::whereIn('MedicalHistoryID', $medicalHistoryIds) ->with(['surgicalOperations']) ->orderBy('DateRecipient', 'DESC') ->get(); } /** * Получить умерших пациентов (исход) */ private function getDeceasedOutcomePatients($branchId, $startDate, $endDate, bool $returnedCount = false, bool $onlyIds = false) { $medicalHistoryIds = MisMigrationPatient::deceasedOutcome($branchId, $startDate, $endDate) ->pluck('rf_MedicalHistoryID') ->unique() ->toArray(); if (empty($medicalHistoryIds)) { if ($returnedCount) return 0; return collect(); } if ($onlyIds) { return $medicalHistoryIds; } $query = MisMedicalHistory::whereIn('MedicalHistoryID', $medicalHistoryIds) ->with(['surgicalOperations']) ->orderBy('DateRecipient', 'DESC'); if ($returnedCount) return $query->count(); else return $query->get(); } /** * Получить пациентов с операциями */ private function getSurgicalPatients(string $status, bool $isHeadOrAdmin, $branchId, $startDate, $endDate, bool $returnedCount = false) { $query = MisSurgicalOperation::where('rf_StationarBranchID', $branchId) ->whereBetween('Date', [$startDate, $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' ]); ObservationPatient::where('rf_medicalhistory_id', $data['id'])->delete(); return response()->json()->setStatusCode(200); } // api/report/unwanted-event public function removeUnwantedEvent(UnwantedEvent $unwantedEvent, Request $request) { $unwantedEvent->delete(); return response()->json()->setStatusCode(200); } }