* переписал функции прототипов в сервисы
* оптимизация доставки контента до клиента * переписал запросы выборок * убрал из подсчета переведенных * добавил сохранение метрикам для вывода в дашборд
This commit is contained in:
@@ -2,119 +2,207 @@
|
||||
|
||||
namespace App\Services;
|
||||
|
||||
use App\Models\MisMigrationPatient;
|
||||
use App\Models\MisMedicalHistory;
|
||||
use App\Models\MisSurgicalOperation;
|
||||
use App\Models\MisMigrationPatient;
|
||||
use App\Models\ObservationPatient;
|
||||
use Illuminate\Support\Collection;
|
||||
use Carbon\Carbon;
|
||||
|
||||
class PatientService
|
||||
{
|
||||
public function getPatientsByType(
|
||||
string $type,
|
||||
?bool $isHeadOrAdmin,
|
||||
?int $branchId,
|
||||
?string $startDate = null,
|
||||
?string $endDate = null,
|
||||
/**
|
||||
* Получить плановых или экстренных пациентов
|
||||
*/
|
||||
public function getPlanOrEmergencyPatients(
|
||||
?string $type,
|
||||
bool $isHeadOrAdmin,
|
||||
int $branchId,
|
||||
DateRange $dateRange,
|
||||
bool $countOnly = false,
|
||||
bool $onlyIds = false
|
||||
): Collection|int|array {
|
||||
// Обрабатываем outcome- типы
|
||||
if (str_starts_with($type, 'outcome-')) {
|
||||
$outcomeType = str_replace('outcome-', '', $type);
|
||||
return $this->getOutcomePatients($branchId, $startDate, $endDate, $outcomeType, $countOnly, $onlyIds);
|
||||
}
|
||||
|
||||
// Обрабатываем обычные типы
|
||||
$method = 'get' . ucfirst($type) . 'Patients';
|
||||
|
||||
if (method_exists($this, $method)) {
|
||||
return $this->$method($isHeadOrAdmin, $branchId, $startDate, $endDate, $countOnly, $onlyIds);
|
||||
}
|
||||
|
||||
throw new \InvalidArgumentException("Unknown patient type: {$type}");
|
||||
}
|
||||
|
||||
public function getPlanPatients(
|
||||
?bool $isHeadOrAdmin,
|
||||
?int $branchId,
|
||||
?string $startDate,
|
||||
?string $endDate,
|
||||
bool $countOnly,
|
||||
bool $onlyIds
|
||||
): Collection|int|array {
|
||||
return $this->getAdmissionPatients('plan', $isHeadOrAdmin, $branchId, $startDate, $endDate, $countOnly, $onlyIds);
|
||||
}
|
||||
|
||||
public function getEmergencyPatients(
|
||||
?bool $isHeadOrAdmin,
|
||||
?int $branchId,
|
||||
?string $startDate,
|
||||
?string $endDate,
|
||||
bool $countOnly,
|
||||
bool $onlyIds
|
||||
): Collection|int|array {
|
||||
return $this->getAdmissionPatients('emergency', $isHeadOrAdmin, $branchId, $startDate, $endDate, $countOnly, $onlyIds);
|
||||
}
|
||||
|
||||
private function getAdmissionPatients(
|
||||
string $admissionType,
|
||||
?bool $isHeadOrAdmin,
|
||||
?int $branchId,
|
||||
?string $startDate,
|
||||
?string $endDate,
|
||||
bool $countOnly,
|
||||
bool $onlyIds
|
||||
): Collection|int|array {
|
||||
$query = $this->getBasePatientsQuery($isHeadOrAdmin, $branchId, $startDate, $endDate);
|
||||
|
||||
if ($admissionType === 'plan') {
|
||||
$query->plan();
|
||||
} else {
|
||||
$query->emergency();
|
||||
}
|
||||
|
||||
return $this->executeQuery($query, $countOnly, $onlyIds);
|
||||
}
|
||||
|
||||
private function getBasePatientsQuery(
|
||||
?bool $isHeadOrAdmin,
|
||||
?int $branchId,
|
||||
?string $startDate,
|
||||
?string $endDate
|
||||
bool $onlyIds = false,
|
||||
bool $includeCurrent = false
|
||||
) {
|
||||
$migrationPatient = new MisMigrationPatient();
|
||||
// Получаем поступивших сегодня
|
||||
$recipientQuery = $this->buildRecipientQuery($type, $isHeadOrAdmin, $branchId, $dateRange);
|
||||
$recipientIds = $recipientQuery->pluck('rf_MedicalHistoryID')->toArray();
|
||||
|
||||
if ($isHeadOrAdmin) {
|
||||
$medicalHistoryIds = $migrationPatient->newQuery()
|
||||
->whereInDepartment($branchId)
|
||||
->whereBetween('DateIngoing', [$startDate, $endDate])
|
||||
// Если нужно добавить уже находящихся в отделении
|
||||
if ($includeCurrent) {
|
||||
$currentIds = MisMigrationPatient::currentlyInTreatment($branchId)
|
||||
->pluck('rf_MedicalHistoryID')
|
||||
->toArray();
|
||||
|
||||
$medicalHistoryIds = array_unique(array_merge($recipientIds, $currentIds));
|
||||
} else {
|
||||
$medicalHistoryIds = $migrationPatient->newQuery()
|
||||
->currentlyInTreatment($branchId)
|
||||
->whereBetween('DateIngoing', [$startDate, $endDate])
|
||||
->pluck('rf_MedicalHistoryID')
|
||||
->toArray();
|
||||
$medicalHistoryIds = $recipientIds;
|
||||
}
|
||||
|
||||
if (empty($medicalHistoryIds)) {
|
||||
return MisMedicalHistory::whereRaw('1=0'); // Пустой запрос
|
||||
if ($countOnly) return 0;
|
||||
if ($onlyIds) return [];
|
||||
return collect();
|
||||
}
|
||||
|
||||
if ($onlyIds) {
|
||||
return $medicalHistoryIds;
|
||||
}
|
||||
|
||||
// Получаем истории
|
||||
$query = MisMedicalHistory::whereIn('MedicalHistoryID', $medicalHistoryIds)
|
||||
->with([
|
||||
'surgicalOperations' => function ($q) use ($dateRange) {
|
||||
$q->whereBetween('Date', [$dateRange->startSql(), $dateRange->endSql()]);
|
||||
},
|
||||
'migrations' => function ($q) use ($branchId) {
|
||||
$q->where('rf_StationarBranchID', $branchId) // укажите поле сортировки
|
||||
->take(1) // берем только одну последнюю
|
||||
->with(['diagnosis' => function ($q) {
|
||||
$q->where('rf_DiagnosTypeID', 3)
|
||||
->take(1)
|
||||
->with('mkb');
|
||||
}]);
|
||||
}
|
||||
])
|
||||
->orderBy('DateRecipient', 'DESC');
|
||||
|
||||
// Фильтруем по типу (план/экстренные)
|
||||
if ($type === 'plan') {
|
||||
$query->plan();
|
||||
} elseif ($type === 'emergency') {
|
||||
$query->emergency();
|
||||
}
|
||||
|
||||
if ($countOnly) {
|
||||
return $query->count();
|
||||
}
|
||||
|
||||
return $query->get()->map(function ($patient) use ($recipientIds, $branchId) {
|
||||
// Добавляем флаг "поступил сегодня"
|
||||
$patient->is_recipient_today = in_array($patient->MedicalHistoryID, $recipientIds);
|
||||
return $patient;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Получить всех пациентов в отделении (поступившие сегодня + уже лечащиеся)
|
||||
*/
|
||||
public function getAllPatientsInDepartment(
|
||||
bool $isHeadOrAdmin,
|
||||
int $branchId,
|
||||
DateRange $dateRange,
|
||||
bool $countOnly = false
|
||||
) {
|
||||
// Поступившие сегодня
|
||||
$recipientIds = $this->buildRecipientQuery(null, $isHeadOrAdmin, $branchId, $dateRange)
|
||||
->pluck('rf_MedicalHistoryID')
|
||||
->toArray();
|
||||
|
||||
// Уже находящиеся на лечении
|
||||
$currentIds = MisMigrationPatient::currentlyInTreatment($branchId)
|
||||
->pluck('rf_MedicalHistoryID')
|
||||
->toArray();
|
||||
|
||||
// Объединяем и убираем дубли
|
||||
$allIds = array_unique(array_merge($recipientIds, $currentIds));
|
||||
|
||||
if (empty($allIds)) {
|
||||
if ($countOnly) return 0;
|
||||
return collect();
|
||||
}
|
||||
|
||||
if ($countOnly) {
|
||||
return count($allIds);
|
||||
}
|
||||
|
||||
return MisMedicalHistory::whereIn('MedicalHistoryID', $allIds)
|
||||
->with(['surgicalOperations' => function ($q) use ($startDate, $endDate) {
|
||||
$q->whereBetween('Date', [$startDate, $endDate]);
|
||||
}])
|
||||
->orderBy('DateRecipient', 'DESC')
|
||||
->get()
|
||||
->map(function ($patient) use ($recipientIds) {
|
||||
$patient->is_recipient_today = in_array($patient->MedicalHistoryID, $recipientIds);
|
||||
return $patient;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Получить пациентов под наблюдением
|
||||
*/
|
||||
public function getObservationPatients(int $departmentId)
|
||||
{
|
||||
$patients = MisMedicalHistory::whereHas('observationPatient', function ($q) use ($departmentId) {
|
||||
$q->where('rf_department_id', $departmentId);
|
||||
})
|
||||
->with(['observationPatient' => function($query) use ($departmentId) {
|
||||
$query->where('rf_department_id', $departmentId)
|
||||
->select(['rf_medicalhistory_id', 'observation_patient_id', 'comment']);
|
||||
}])
|
||||
->orderBy('DateRecipient', 'DESC')
|
||||
->get();
|
||||
|
||||
return $patients->map(function ($patient) {
|
||||
$patient->comment = $patient->observationPatient
|
||||
->pluck('comment')
|
||||
->filter()
|
||||
->implode('; ');
|
||||
return $patient;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Получить выбывших пациентов
|
||||
*/
|
||||
public function getOutcomePatients(
|
||||
int $branchId,
|
||||
DateRange $dateRange,
|
||||
string $outcomeType = 'all'
|
||||
) {
|
||||
$methodMap = [
|
||||
'discharged' => 'discharged',
|
||||
'transferred' => 'transferred',
|
||||
'deceased' => 'deceasedOutcome',
|
||||
'all' => 'outcomePatients',
|
||||
];
|
||||
|
||||
$method = $methodMap[$outcomeType] ?? 'outcomePatients';
|
||||
|
||||
$medicalHistoryIds = MisMigrationPatient::{$method}($branchId, $dateRange)
|
||||
->pluck('rf_MedicalHistoryID')
|
||||
->unique()
|
||||
->toArray();
|
||||
|
||||
if (empty($medicalHistoryIds)) {
|
||||
return collect();
|
||||
}
|
||||
|
||||
return MisMedicalHistory::whereIn('MedicalHistoryID', $medicalHistoryIds)
|
||||
->with(['surgicalOperations' => function ($query) use ($startDate, $endDate) {
|
||||
$query->whereBetween('Date', [$startDate, $endDate]);
|
||||
}])
|
||||
->orderBy('DateRecipient', 'DESC');
|
||||
->with(['surgicalOperations'])
|
||||
->orderBy('DateRecipient', 'DESC')
|
||||
->get()
|
||||
->map(function ($patient) {
|
||||
return $this->addOutcomeInfo($patient);
|
||||
});
|
||||
}
|
||||
|
||||
private function executeQuery($query, bool $countOnly, bool $onlyIds): Collection|int|array
|
||||
{
|
||||
if ($onlyIds) {
|
||||
return $query->pluck('MedicalHistoryID')->toArray();
|
||||
}
|
||||
/**
|
||||
* Получить пациентов с операциями
|
||||
*/
|
||||
public function getSurgicalPatients(
|
||||
string $type,
|
||||
int $branchId,
|
||||
DateRange $dateRange,
|
||||
bool $countOnly = false
|
||||
) {
|
||||
$query = MisMedicalHistory::whereHas('surgicalOperations', function ($q) use ($type, $branchId, $dateRange) {
|
||||
$q->where('rf_StationarBranchID', $branchId)
|
||||
->whereBetween('Date', [$dateRange->startSql(), $dateRange->endSql()]);
|
||||
|
||||
if ($type === 'plan') {
|
||||
$q->where('rf_TypeSurgOperationInTimeID', 6);
|
||||
} else {
|
||||
$q->whereIn('rf_TypeSurgOperationInTimeID', [4, 5]);
|
||||
}
|
||||
});
|
||||
|
||||
if ($countOnly) {
|
||||
return $query->count();
|
||||
@@ -123,224 +211,18 @@ class PatientService
|
||||
return $query->get();
|
||||
}
|
||||
|
||||
public function getObservationPatients(int $departmentId): Collection
|
||||
/**
|
||||
* Получить текущих пациентов
|
||||
*/
|
||||
public function getCurrentPatients(int $branchId, bool $countOnly = false)
|
||||
{
|
||||
return ObservationPatient::where('rf_department_id', $departmentId)
|
||||
->with(['medicalHistory'])
|
||||
->get()
|
||||
->map(function ($observation) {
|
||||
$patient = $observation->medicalHistory;
|
||||
$patient->observation_comment = $observation->comment;
|
||||
return $patient;
|
||||
});
|
||||
}
|
||||
|
||||
public function getOutcomePatients(int $branchId, string $startDate, string $endDate, string $outcomeType, $countOnly = false, $onlyIds = false): Collection|int
|
||||
{
|
||||
return match($outcomeType) {
|
||||
'discharged' => $this->getDischargedOutcomePatients($branchId, $startDate, $endDate, $countOnly, $onlyIds),
|
||||
'transferred' => $this->getTransferredOutcomePatients($branchId, $startDate, $endDate, $countOnly, $onlyIds),
|
||||
'deceased' => $this->getDeceasedOutcomePatients($branchId, $startDate, $endDate, $countOnly, $onlyIds),
|
||||
default => throw new \InvalidArgumentException("Неизвестный тип исхода: {$outcomeType}")
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Получить всех выбывших пациентов
|
||||
*/
|
||||
public function getAllOutcomePatients(
|
||||
int $branchId,
|
||||
string $startDate,
|
||||
string $endDate,
|
||||
bool $countOnly = false
|
||||
): Collection|int {
|
||||
$migrationPatient = new MisMigrationPatient();
|
||||
|
||||
// Получаем миграции выбывших пациентов за период
|
||||
$migrations = $migrationPatient->newQuery()
|
||||
->outcomePatients($branchId, $startDate, $endDate)
|
||||
->select('rf_MedicalHistoryID', 'rf_kl_VisitResultID', 'DateOut')
|
||||
->get()
|
||||
->groupBy('rf_MedicalHistoryID');
|
||||
|
||||
if ($migrations->isEmpty()) {
|
||||
return $countOnly ? 0 : collect();
|
||||
}
|
||||
|
||||
$medicalHistoryIds = $migrations->keys()->toArray();
|
||||
|
||||
$query = MisMedicalHistory::whereIn('MedicalHistoryID', $medicalHistoryIds)
|
||||
->with(['surgicalOperations'])
|
||||
->orderBy('DateRecipient', 'DESC');
|
||||
|
||||
if ($countOnly) {
|
||||
return $query->count();
|
||||
}
|
||||
|
||||
$patients = $query->get();
|
||||
|
||||
return $this->addOutcomeInfoToPatients($patients, $migrations);
|
||||
}
|
||||
|
||||
/**
|
||||
* Получить миграции выбывших пациентов
|
||||
*/
|
||||
private function getOutcomeMigrations(int $branchId, string $startDate, string $endDate): Collection
|
||||
{
|
||||
$migrationPatient = new MisMigrationPatient();
|
||||
|
||||
return $migrationPatient->newQuery()
|
||||
->outcomePatients($branchId, $startDate, $endDate)
|
||||
->select('rf_MedicalHistoryID', 'rf_kl_VisitResultID', 'DateOut')
|
||||
->get()
|
||||
->groupBy('rf_MedicalHistoryID');
|
||||
}
|
||||
|
||||
/**
|
||||
* Добавить информацию о выбытии к пациентам
|
||||
*/
|
||||
private function addOutcomeInfoToPatients(Collection $patients, Collection $migrations): Collection
|
||||
{
|
||||
return $patients->map(function ($patient) use ($migrations) {
|
||||
$patientMigrations = $migrations->get($patient->MedicalHistoryID, collect());
|
||||
|
||||
if ($patientMigrations->isNotEmpty()) {
|
||||
$latestMigration = $patientMigrations->sortByDesc('DateOut')->first();
|
||||
$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(int $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 . ')'
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Получить выписанных пациентов
|
||||
*/
|
||||
public function getDischargedOutcomePatients(
|
||||
int $branchId,
|
||||
string $startDate,
|
||||
string $endDate,
|
||||
bool $countOnly = false,
|
||||
bool $onlyIds = false
|
||||
): Collection|array|int {
|
||||
return $this->getSpecificOutcomePatients('discharged', $branchId, $startDate, $endDate, $onlyIds, $countOnly);
|
||||
}
|
||||
|
||||
/**
|
||||
* Получить переведенных пациентов
|
||||
*/
|
||||
public function getTransferredOutcomePatients(
|
||||
int $branchId,
|
||||
string $startDate,
|
||||
string $endDate,
|
||||
bool $countOnly = false,
|
||||
bool $onlyIds = false
|
||||
): Collection|array|int {
|
||||
return $this->getSpecificOutcomePatients('transferred', $branchId, $startDate, $endDate, $onlyIds, $countOnly);
|
||||
}
|
||||
|
||||
/**
|
||||
* Получить умерших пациентов
|
||||
*/
|
||||
public function getDeceasedOutcomePatients(
|
||||
int $branchId,
|
||||
string $startDate,
|
||||
string $endDate,
|
||||
bool $countOnly = false,
|
||||
bool $onlyIds = false
|
||||
): Collection|int|array {
|
||||
return $this->getSpecificOutcomePatients('deceased', $branchId, $startDate, $endDate, $onlyIds, $countOnly);
|
||||
}
|
||||
|
||||
/**
|
||||
* Общий метод для получения пациентов с определенным типом выбытия
|
||||
*/
|
||||
private function getSpecificOutcomePatients(
|
||||
string $type,
|
||||
int $branchId,
|
||||
string $startDate,
|
||||
string $endDate,
|
||||
bool $onlyIds = false,
|
||||
bool $countOnly = false
|
||||
): Collection|int|array {
|
||||
$migrationPatient = new MisMigrationPatient();
|
||||
|
||||
switch ($type) {
|
||||
case 'discharged':
|
||||
$query = $migrationPatient->newQuery()->discharged($branchId, $startDate, $endDate);
|
||||
break;
|
||||
case 'transferred':
|
||||
$query = $migrationPatient->newQuery()->transferred($branchId, $startDate, $endDate);
|
||||
break;
|
||||
case 'deceased':
|
||||
$query = $migrationPatient->newQuery()->deceasedOutcome($branchId, $startDate, $endDate);
|
||||
break;
|
||||
default:
|
||||
throw new \InvalidArgumentException("Неизвестный тип выбытия: {$type}");
|
||||
}
|
||||
|
||||
$medicalHistoryIds = $query->pluck('rf_MedicalHistoryID')->unique()->toArray();
|
||||
|
||||
if (empty($medicalHistoryIds)) {
|
||||
if ($countOnly) return 0;
|
||||
if ($onlyIds) return [];
|
||||
return collect();
|
||||
}
|
||||
|
||||
if ($onlyIds) {
|
||||
return $medicalHistoryIds;
|
||||
}
|
||||
|
||||
$patients = MisMedicalHistory::whereIn('MedicalHistoryID', $medicalHistoryIds)
|
||||
->with(['surgicalOperations'])
|
||||
->orderBy('DateRecipient', 'DESC');
|
||||
|
||||
if ($countOnly) {
|
||||
return $patients->count();
|
||||
}
|
||||
|
||||
return $patients->get();
|
||||
}
|
||||
|
||||
/**
|
||||
* Получить пациентов, находящихся на лечении
|
||||
*/
|
||||
public function getCurrentPatients(
|
||||
int $branchId,
|
||||
bool $countOnly = false,
|
||||
bool $onlyIds = false
|
||||
): Collection|int|array {
|
||||
$migrationPatient = new MisMigrationPatient();
|
||||
|
||||
$medicalHistoryIds = $migrationPatient->newQuery()
|
||||
->currentlyInTreatment($branchId)
|
||||
$medicalHistoryIds = MisMigrationPatient::currentlyInTreatment($branchId)
|
||||
->pluck('rf_MedicalHistoryID')
|
||||
->unique()
|
||||
->toArray();
|
||||
|
||||
if (empty($medicalHistoryIds)) {
|
||||
if ($countOnly) return 0;
|
||||
if ($onlyIds) return [];
|
||||
return collect();
|
||||
}
|
||||
|
||||
if ($onlyIds) {
|
||||
return $medicalHistoryIds;
|
||||
return $countOnly ? 0 : collect();
|
||||
}
|
||||
|
||||
$query = MisMedicalHistory::whereIn('MedicalHistoryID', $medicalHistoryIds)
|
||||
@@ -356,94 +238,127 @@ class PatientService
|
||||
}
|
||||
|
||||
/**
|
||||
* Получить пациентов с операциями
|
||||
* Собрать базовый запрос для пациентов
|
||||
*/
|
||||
public function getSurgicalPatients(
|
||||
string $status,
|
||||
private function buildPatientQuery(
|
||||
?string $type,
|
||||
bool $isHeadOrAdmin,
|
||||
int $branchId,
|
||||
string $startDate,
|
||||
string $endDate,
|
||||
bool $countOnly = false
|
||||
): Collection|int {
|
||||
$query = MisSurgicalOperation::where('rf_StationarBranchID', $branchId)
|
||||
->whereBetween('Date', [$startDate, $endDate])
|
||||
->orderBy('Date', 'DESC');
|
||||
|
||||
if ($status === 'plan') {
|
||||
$query->where('rf_TypeSurgOperationInTimeID', 6);
|
||||
DateRange $dateRange
|
||||
) {
|
||||
if ($isHeadOrAdmin) {
|
||||
$query = MisMigrationPatient::whereInDepartment($branchId)
|
||||
->whereBetween('DateIngoing', [$dateRange->startSql(), $dateRange->endSql()]);
|
||||
} else {
|
||||
$query->whereIn('rf_TypeSurgOperationInTimeID', [4, 5]);
|
||||
$query = MisMigrationPatient::currentlyInTreatment($branchId)
|
||||
->whereBetween('DateIngoing', [$dateRange->startSql(), $dateRange->endSql()]);
|
||||
}
|
||||
|
||||
if ($countOnly) {
|
||||
return $query->count();
|
||||
$medicalHistoryIds = $query->pluck('rf_MedicalHistoryID')->toArray();
|
||||
|
||||
if (empty($medicalHistoryIds)) {
|
||||
return MisMedicalHistory::whereRaw('1 = 0');
|
||||
}
|
||||
|
||||
return $query->get();
|
||||
}
|
||||
$query = MisMedicalHistory::whereIn('MedicalHistoryID', $medicalHistoryIds);
|
||||
|
||||
/**
|
||||
* Получить пациентов (плановых или экстренных), которые были в отделении в течение периода
|
||||
*/
|
||||
public function getPatientsInDepartmentDuringPeriod(
|
||||
?string $patientType, // 'plan', 'emergency', null (все)
|
||||
?bool $isHeadOrAdmin,
|
||||
?int $branchId,
|
||||
?string $startDate,
|
||||
?string $endDate,
|
||||
bool $countOnly = false,
|
||||
bool $onlyIds = false,
|
||||
bool $today = false
|
||||
): Collection|int|array {
|
||||
// Используем скоуп inDepartment из модели MisMedicalHistory
|
||||
$query = MisMedicalHistory::query()
|
||||
->whereHas('migrations', function ($q) use ($branchId, $startDate, $endDate) {
|
||||
$q->where('rf_StationarBranchID', $branchId)
|
||||
->where('rf_MedicalHistoryID', '<>', 0)
|
||||
->where(function ($subQ) use ($startDate, $endDate) {
|
||||
// Пациент находился в отделении в течение периода
|
||||
// 1. Поступил в течение периода
|
||||
$subQ->whereBetween('DateIngoing', [$startDate, $endDate])
|
||||
// 2. Или выбыл в течение периода
|
||||
->orWhereBetween('DateOut', [$startDate, $endDate])
|
||||
// 3. Или находился в отделении в течение всего периода
|
||||
->orWhere(function ($innerQ) use ($startDate, $endDate) {
|
||||
$innerQ->where('DateIngoing', '<=', $startDate)
|
||||
->where(function ($deepQ) use ($endDate) {
|
||||
$deepQ->where('DateOut', '>=', $endDate)
|
||||
->orWhereNull('DateOut')
|
||||
->orWhere('DateOut', '1900-01-01');
|
||||
});
|
||||
});
|
||||
});
|
||||
})
|
||||
->with(['surgicalOperations' => function ($query) use ($startDate, $endDate) {
|
||||
$query->whereBetween('Date', [$startDate, $endDate]);
|
||||
}])
|
||||
->orderBy('DateRecipient', 'DESC');
|
||||
|
||||
// Фильтруем по типу (план/экстренность)
|
||||
if ($patientType === 'plan') {
|
||||
if ($type === 'plan') {
|
||||
$query->plan();
|
||||
} elseif ($patientType === 'emergency') {
|
||||
} elseif ($type === 'emergency') {
|
||||
$query->emergency();
|
||||
}
|
||||
|
||||
// Для врача добавляем условие "все еще в отделении"
|
||||
if (!$isHeadOrAdmin && !$today) {
|
||||
if (!$isHeadOrAdmin && !in_array($type, ['discharged', 'transferred', 'deceased'])) {
|
||||
$query->currentlyHospitalized();
|
||||
}
|
||||
|
||||
if ($onlyIds) {
|
||||
return $query->select('MedicalHistoryID')
|
||||
->pluck('MedicalHistoryID')->values();
|
||||
return $query;
|
||||
}
|
||||
|
||||
/**
|
||||
* Построить запрос для поступивших пациентов
|
||||
*/
|
||||
private function buildRecipientQuery(
|
||||
?string $type,
|
||||
bool $isHeadOrAdmin,
|
||||
int $branchId,
|
||||
DateRange $dateRange
|
||||
) {
|
||||
// Разная логика для заведующего и врача
|
||||
if ($isHeadOrAdmin) {
|
||||
// Заведующий: все поступившие за период
|
||||
$query = MisMigrationPatient::whereInDepartment($branchId)
|
||||
->whereBetween('DateIngoing', [$dateRange->startSql(), $dateRange->endSql()]);
|
||||
} else {
|
||||
// Врач: только поступившие за сутки
|
||||
$query = MisMigrationPatient::whereInDepartment($branchId)
|
||||
->whereBetween('DateIngoing', [$dateRange->startSql(), $dateRange->endSql()]);
|
||||
}
|
||||
|
||||
if ($countOnly) {
|
||||
return $query->count();
|
||||
return $query;
|
||||
}
|
||||
|
||||
/**
|
||||
* Добавить информацию об исходе пациенту
|
||||
*/
|
||||
private function addOutcomeInfo(MisMedicalHistory $patient)
|
||||
{
|
||||
$latestMigration = $patient->migrations
|
||||
->whereNotNull('DateOut')
|
||||
->where('DateOut', '<>', '1900-01-01')
|
||||
->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 $query->get();
|
||||
return $patient;
|
||||
}
|
||||
|
||||
/**
|
||||
* Получить количество пациентов по типу с учетом уже находящихся в отделении
|
||||
*/
|
||||
public function getPatientsCountWithCurrent(
|
||||
?string $type,
|
||||
bool $isHeadOrAdmin,
|
||||
int $branchId,
|
||||
DateRange $dateRange
|
||||
): int {
|
||||
// Поступившие сегодня указанного типа
|
||||
$recipientCount = $this->buildRecipientQuery($type, $isHeadOrAdmin, $branchId, $dateRange)
|
||||
->count();
|
||||
|
||||
// Если нужны плановые/экстренные среди уже лечащихся
|
||||
$currentCount = 0;
|
||||
if ($type === 'plan' || $type === 'emergency') {
|
||||
$currentIds = MisMigrationPatient::currentlyInTreatment($branchId)
|
||||
->pluck('rf_MedicalHistoryID')
|
||||
->toArray();
|
||||
|
||||
if (!empty($currentIds)) {
|
||||
$currentCount = MisMedicalHistory::whereIn('MedicalHistoryID', $currentIds)
|
||||
->when($type === 'plan', fn($q) => $q->plan())
|
||||
->when($type === 'emergency', fn($q) => $q->emergency())
|
||||
->count();
|
||||
}
|
||||
}
|
||||
|
||||
return $currentCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* Получить название типа исхода
|
||||
*/
|
||||
private function getOutcomeTypeName(int $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 . ')'
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user