* работа над функционалом автоматического заполнения

* исправил фантомный сдвиг даты
* переделал получение ФИО врачей из отделений
* добавил возможность поиска врача
* переписал сохранение отчета
This commit is contained in:
brusnitsyn
2026-02-05 17:11:43 +09:00
parent eab78a0291
commit 10fb138c30
22 changed files with 1192 additions and 654 deletions

View File

@@ -185,12 +185,12 @@ class ReportController extends Controller
}
}
$isRangeOneDay = $this->dateService->isRangeOneDay($startDate, $endDate);
$isRangeOneDay = $this->dateRangeService->isRangeOneDay($startDate, $endDate);
$date = $isHeadOrAdmin ? [
$this->dateService->parseDate($isRangeOneDay ? $endDate : $startDate)->getTimestampMs(),
$this->dateService->parseDate($endDate)->getTimestampMs()
] : $this->dateService->parseDate($endDate)->getTimestampMs();
$this->dateRangeService->parseDate($isRangeOneDay ? $endDate : $startDate)->getTimestampMs(),
$this->dateRangeService->parseDate($endDate)->getTimestampMs()
] : $this->dateRangeService->parseDate($endDate)->getTimestampMs();
return response()->json([
'department' => [
@@ -285,72 +285,6 @@ class ReportController extends Controller
return $count;
}
/**
* Получить количество пациентов из снапшотов
*/
private function getCountFromSnapshots(string $type, array $reportIds)
{
return match($type) {
'plan' => MedicalHistorySnapshot::whereIn('rf_report_id', $reportIds)
->where('patient_type', 'plan')
->distinct('rf_medicalhistory_id')
->count('rf_medicalhistory_id'),
'emergency' => MedicalHistorySnapshot::whereIn('rf_report_id', $reportIds)
->where('patient_type', 'emergency')
->distinct('rf_medicalhistory_id')
->count('rf_medicalhistory_id'),
'outcome' => MedicalHistorySnapshot::whereIn('rf_report_id', $reportIds)
->whereIn('patient_type', ['discharged', 'transferred', 'deceased'])
->distinct('rf_medicalhistory_id')
->count('rf_medicalhistory_id'),
'deceased' => MedicalHistorySnapshot::whereIn('rf_report_id', $reportIds)
->where('patient_type', 'deceased')
->distinct('rf_medicalhistory_id')
->count('rf_medicalhistory_id'),
'discharged' => MedicalHistorySnapshot::whereIn('rf_report_id', $reportIds)
->where('patient_type', 'discharged')
->distinct('rf_medicalhistory_id')
->count('rf_medicalhistory_id'),
'transferred' => MedicalHistorySnapshot::whereIn('rf_report_id', $reportIds)
->where('patient_type', 'transferred')
->distinct('rf_medicalhistory_id')
->count('rf_medicalhistory_id'),
'recipient' => MedicalHistorySnapshot::whereIn('rf_report_id', $reportIds)
->where('patient_type', 'recipient')
->distinct('rf_medicalhistory_id')
->count('rf_medicalhistory_id'),
default => 0
};
}
/**
* Получить ID пациентов на лечении из снапшотов
*/
private function getCurrentPatientsFromSnapshots(array $reportIds, $branchId)
{
// Получаем ID всех пациентов из снапшотов за период
$allSnapshotPatientIds = MedicalHistorySnapshot::whereIn('rf_report_id', $reportIds)
->pluck('rf_medicalhistory_id')
->unique()
->toArray();
if (empty($allSnapshotPatientIds)) {
return 0;
}
// Получаем ID выбывших пациентов
$outcomePatientIds = MedicalHistorySnapshot::whereIn('rf_report_id', $reportIds)
->whereIn('patient_type', ['discharged', 'transferred', 'deceased'])
->pluck('rf_medicalhistory_id')
->unique()
->toArray();
// Текущие пациенты = все пациенты - выбывшие
$currentPatientIds = array_diff($allSnapshotPatientIds, $outcomePatientIds);
return count($currentPatientIds);
}
/**
* Получить ID поступивших пациентов из снапшотов
*/
@@ -365,33 +299,6 @@ class ReportController extends Controller
return $recipientIds;
}
// /**
// * Получить отчеты по промежутку дат (оптимизированная версия)
// */
// private function getReportsForDateRange($departmentId, $startDate, $endDate)
// {
// $start = Carbon::parse($startDate);
// $end = Carbon::parse($endDate);
//
// // Если промежуток большой, ограничиваем количество отчетов
// $daysDiff = $start->diffInDays($end);
//
// if ($daysDiff > 30) {
// // Для больших промежутков берем только последние отчеты
// return Report::where('rf_department_id', $departmentId)
// ->whereBetween('created_at', [$start, $end])
// ->orderBy('created_at', 'DESC')
// ->take(30) // Ограничиваем количеством
// ->get()
// ->reverse(); // Возвращаем в правильном порядке
// }
//
// return Report::where('rf_department_id', $departmentId)
// ->whereBetween('created_at', [$start, $end])
// ->orderBy('created_at', 'ASC')
// ->get();
// }
public function store(Request $request)
{
$user = Auth::user();
@@ -408,7 +315,8 @@ class ReportController extends Controller
'observationPatients' => 'nullable',
'departmentId' => 'required|integer',
'unwantedEvents' => 'nullable|array',
'dates' => 'required|array',
'startAt' => 'required|integer',
'endAt' => 'required|integer',
'userId' => 'required|integer',
'reportId' => 'nullable'
]);
@@ -417,7 +325,7 @@ class ReportController extends Controller
$unwantedEvents = $data['unwantedEvents'];
// Определяем даты в зависимости от роли
[$startDate, $endDate] = $this->getDateRangeForRole($user, $data['dates'][0], $data['dates'][1]);
$dateRange = $this->dateRangeService->getDateRangeFromRequest($request, $user);
$metriks = [];
foreach ($metrics as $key => $value) {
@@ -429,6 +337,57 @@ class ReportController extends Controller
$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']) {
@@ -483,6 +442,17 @@ class ReportController extends Controller
$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(
@@ -519,11 +489,21 @@ class ReportController extends Controller
$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),
]
);
// Сохраняем снимок для каждого типа пациентов
// 1. Плановые
$planIds = $this->getPlanOrEmergencyPatients('plan', false, $branchId, $startDate, $endDate, false, false, true);
// Планово
//$this->getPlanOrEmergencyPatients('plan', false, $branchId, $dateRange->startSql(), $dateRange->endSql(), false, false, true);
foreach ($planIds as $id) {
MedicalHistorySnapshot::create([
'rf_report_id' => $report->report_id,
@@ -531,9 +511,20 @@ class ReportController extends Controller
'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,
]
);
// 2. Экстренные
$emergencyIds = $this->getPlanOrEmergencyPatients('emergency', false, $branchId, $startDate, $endDate, false, false, true);
//$this->getPlanOrEmergencyPatients('emergency', false, $branchId, $startDate, $endDate, false, false, true);
// Экстренно
foreach ($emergencyIds as $id) {
MedicalHistorySnapshot::create([
'rf_report_id' => $report->report_id,
@@ -541,9 +532,19 @@ class ReportController extends Controller
'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,
]
);
// 3. Выписанные
$dischargedIds = $this->getDischargedPatients($branchId, $startDate, $endDate, true);
//$this->getDischargedPatients($branchId, $startDate, $endDate, true);
foreach ($dischargedIds as $id) {
MedicalHistorySnapshot::create([
'rf_report_id' => $report->report_id,
@@ -551,9 +552,19 @@ class ReportController extends Controller
'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),
]
);
// 4. Переведенные
$transferredIds = $this->getTransferredPatients($branchId, $startDate, $endDate, true);
//$this->getTransferredPatients($branchId, $startDate, $endDate, true);
foreach ($transferredIds as $id) {
MedicalHistorySnapshot::create([
'rf_report_id' => $report->report_id,
@@ -561,9 +572,19 @@ class ReportController extends Controller
'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),
]
);
// 5. Умершие
$deceasedIds = $this->getDeceasedOutcomePatients($branchId, $startDate, $endDate, false, true);
//$this->getDeceasedOutcomePatients($branchId, $startDate, $endDate, false, true);
foreach ($deceasedIds as $id) {
MedicalHistorySnapshot::create([
'rf_report_id' => $report->report_id,
@@ -571,19 +592,29 @@ class ReportController extends Controller
'patient_type' => 'deceased'
]);
}
// 5. Поступившие
$recipientIds = $this->getPlanOrEmergencyPatients(
null,
$isHeadOrAdmin,
$branchId,
$startDate,
$endDate,
false,
true,
true,
today: true
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,
@@ -591,8 +622,19 @@ class ReportController extends Controller
'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),
]
);
// 6. Находящиеся на лечении
// 7. Находящиеся на лечении
// $currentIds = $this->getCurrentPatients($branchId, false, true);
// foreach ($currentIds as $id) {
// MedicalHistorySnapshot::create([
@@ -651,59 +693,6 @@ class ReportController extends Controller
return response()->json($count);
}
/**
* Определить диапазон дат в зависимости от роли
*/
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);
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');
}
}
// Если даты не переданы - логика по умолчанию в зависимости от роли
else {
// Для заведующего или администратора - сутки
if ($user->isHeadOfDepartment() || $user->isAdmin()) {
$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');
}
// Для врача - только сутки (вчера 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];
}
/**
* Получить пациентов (плановых или экстренных)
*/
@@ -784,61 +773,6 @@ class ReportController extends Controller
}
}
/**
* Получить пациентов под наблюдением
*/
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();
}
/**
* Получить всех выбывших пациентов
*/
@@ -896,54 +830,6 @@ class ReportController extends Controller
};
}
/**
* Получить выписанных пациентов
*/
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();
}
/**
* Получить умерших пациентов (исход)
*/
@@ -1050,8 +936,12 @@ class ReportController extends Controller
$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()
->inMyDepartment()
->whereNotIn('LPUDoctorID', [0, 1])
->get();
return response()->json([
@@ -1075,184 +965,4 @@ class ReportController extends Controller
->orderBy('created_at', 'ASC')
->get();
}
/**
* Получить плановых/экстренных пациентов из снапшотов через реплику
*/
private function getPatientsFromSnapshotsUsingReplica(string $status, array $reportIds, $branchId, $startDate, $endDate)
{
// Получаем ID пациентов из снапшотов
$patientType = $status === 'plan' ? 'plan' : 'emergency';
$medicalHistoryIds = MedicalHistorySnapshot::whereIn('rf_report_id', $reportIds)
->where('patient_type', $patientType)
->pluck('rf_medicalhistory_id')
->unique()
->toArray();
if (empty($medicalHistoryIds)) {
return collect();
}
// Используем существующие скоупы для получения данных из реплики
$query = MisMedicalHistory::whereIn('MedicalHistoryID', $medicalHistoryIds)
->with(['surgicalOperations' => function ($query) use ($startDate, $endDate) {
$query->whereBetween('Date', [$startDate, $endDate]);
}])
->orderBy('DateRecipient', 'DESC');
// Применяем те же фильтры
if ($status === 'plan') {
$query->plan();
} else {
$query->emergency();
}
return $query->get();
}
/**
* Получить пациентов под наблюдением из снапшотов через реплику
*/
private function getObservationPatientsFromSnapshotsUsingReplica($userDepartmentId, array $reportIds)
{
// Получаем ID пациентов из снапшотов наблюдения
$medicalHistoryIds = ObservationPatient::whereIn('rf_report_id', $reportIds)
->pluck('rf_medicalhistory_id')
->unique()
->toArray();
if (empty($medicalHistoryIds)) {
return collect();
}
// Используем существующий метод с фильтрацией по ID из снапшотов
$patients = MisMedicalHistory::whereIn('MedicalHistoryID', $medicalHistoryIds)
->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 getOutcomePatientsFromSnapshotsUsingReplica(string $outcomeType, array $reportIds, $branchId, $startDate, $endDate)
{
// Получаем ID пациентов из снапшотов исходов
$medicalHistoryIds = MedicalHistorySnapshot::whereIn('rf_report_id', $reportIds)
->where('patient_type', $outcomeType)
->pluck('rf_medicalhistory_id')
->unique()
->toArray();
if (empty($medicalHistoryIds)) {
return collect();
}
// Используем соответствующий метод для получения данных из реплики
return match($outcomeType) {
'discharged' => $this->getDischargedPatientsByIds($medicalHistoryIds, $branchId),
'transferred' => $this->getTransferredPatientsByIds($medicalHistoryIds, $branchId),
'deceased' => $this->getDeceasedPatientsByIds($medicalHistoryIds, $branchId),
default => collect()
};
}
/**
* Получить выписанных пациентов по ID из снапшотов
*/
private function getDischargedPatientsByIds(array $medicalHistoryIds, $branchId)
{
return MisMedicalHistory::whereIn('MedicalHistoryID', $medicalHistoryIds)
->with(['surgicalOperations'])
->orderBy('DateRecipient', 'DESC')
->get()
->map(function ($patient) use ($branchId) {
// Получаем информацию о выписке
$migration = $patient->migrations
->where('rf_kl_VisitResultID', 'in', [1, 7, 8, 9, 10, 11, 48, 49, 124])
->whereNotNull('DateOut')
->sortByDesc('DateOut')
->first();
if ($migration) {
$patient->outcome_type = $this->getOutcomeTypeName($migration->rf_kl_VisitResultID);
$patient->outcome_date = $migration->DateOut;
$patient->visit_result_id = $migration->rf_kl_VisitResultID;
}
return $patient;
});
}
/**
* Получить переведенных пациентов по ID из снапшотов
*/
private function getTransferredPatientsByIds(array $medicalHistoryIds, $branchId)
{
return MisMedicalHistory::whereIn('MedicalHistoryID', $medicalHistoryIds)
->with(['surgicalOperations'])
->orderBy('DateRecipient', 'DESC')
->get()
->map(function ($patient) use ($branchId) {
// Получаем информацию о переводе
$migration = $patient->migrations
->where('rf_kl_VisitResultID', 'in', [2, 3, 4, 12, 13, 14])
->whereNotNull('DateOut')
->sortByDesc('DateOut')
->first();
if ($migration) {
$patient->outcome_type = $this->getOutcomeTypeName($migration->rf_kl_VisitResultID);
$patient->outcome_date = $migration->DateOut;
$patient->visit_result_id = $migration->rf_kl_VisitResultID;
}
return $patient;
});
}
/**
* Получить умерших пациентов по ID из снапшотов
*/
private function getDeceasedPatientsByIds(array $medicalHistoryIds, $branchId)
{
return MisMedicalHistory::whereIn('MedicalHistoryID', $medicalHistoryIds)
->with(['surgicalOperations'])
->orderBy('DateRecipient', 'DESC')
->get()
->map(function ($patient) use ($branchId) {
// Получаем информацию о смерти
$migration = $patient->migrations
->where('rf_kl_VisitResultID', 'in', [5, 6, 15, 16])
->whereNotNull('DateOut')
->sortByDesc('DateOut')
->first();
if ($migration) {
$patient->outcome_type = $this->getOutcomeTypeName($migration->rf_kl_VisitResultID);
$patient->outcome_date = $migration->DateOut;
$patient->visit_result_id = $migration->rf_kl_VisitResultID;
}
return $patient;
});
}
}