* изменил таблицы в основном отчете

* изменил метод сохранения пациентов основного отчета
This commit is contained in:
brusnitsyn
2026-05-07 18:00:43 +09:00
parent 723ccee8d3
commit bb9e67ab3d
25 changed files with 1438 additions and 52 deletions

View File

@@ -0,0 +1,118 @@
<?php
namespace App\Http\Controllers\Web;
use App\Http\Controllers\Controller;
use App\Http\Resources\MedicalHistoryResource;
use App\Models\Department;
use App\Models\ReportDuty;
use App\Models\ReportNurse;
use App\Services\DateRangeService;
use App\Services\DutyMedicalHistoryService;
use App\Services\DutyReportService;
use App\Services\MedicalHistoryService;
use App\Services\NurseMedicalHistoryService;
use App\Services\NurseReportService;
use App\Services\UnifiedMedicalHistoryService;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Inertia\Inertia;
class DutyReportController extends Controller
{
public function __construct(
protected DateRangeService $dateRangeService,
protected MedicalHistoryService $medicalHistoryService,
protected DutyMedicalHistoryService $dutyMedicalHistoryService,
protected DutyReportService $dutyReportService,
protected NurseMedicalHistoryService $nurseMedicalHistoryService
)
{}
/**
* Получение базовой информации для заполнения отчета для дежурного
* @param Request $request
* @return \Inertia\Response
*/
public function index(Request $request)
{
$user = Auth::user();
$departmentId = $request->query('departmentId', $user->department->department_id);
$department = Department::where('department_id', $departmentId)->firstOrFail();
$dateRange = $this->dateRangeService->getDateRangeFromRequest($request, $user);
// Проверяем, есть ли отчет за этот период
$isPastPeriod = $this->dateRangeService->isPastPeriod($dateRange);
$existsReport = ReportDuty::where('rf_department_id', $departmentId)
->where('period_end', '>', $dateRange->startSql())
->where('period_end', '<=', $dateRange->endSql())
->exists();
$hasReport = $existsReport && $isPastPeriod;
if ($hasReport) {
$inDepartmentHistories = $this->dutyMedicalHistoryService->getDepartmentHistories($dateRange, $department->rf_mis_department_id);
$recipientHistories = $this->dutyMedicalHistoryService->getRecipientHistories($dateRange, $department->rf_mis_department_id);
$dischargedHistories = $this->dutyMedicalHistoryService->getDischargedHistories($dateRange, $department->rf_mis_department_id);
$deceasedHistories = $this->dutyMedicalHistoryService->getDeceasedHistories($dateRange, $department->rf_mis_department_id);
$transferredHistories = $this->dutyMedicalHistoryService->getTransferredHistories($dateRange, $department->rf_mis_department_id);
} else if ($this->dateRangeService->isPastPeriod($dateRange)) {
$inDepartmentHistories = collect([]);
$recipientHistories = collect([]);
$dischargedHistories = collect([]);
$deceasedHistories = collect([]);
$transferredHistories = collect([]);
} else {
$inDepartmentHistories = MedicalHistoryResource::collection(
$this->medicalHistoryService->getDepartmentHistories($dateRange, $department->rf_mis_department_id)
);
$plannedHistories = MedicalHistoryResource::collection(
$this->medicalHistoryService->getPlannedHistories($dateRange, $department->rf_mis_department_id)
);
$emergencyHistories = MedicalHistoryResource::collection(
$this->medicalHistoryService->getEmergencyHistories($dateRange, $department->rf_mis_department_id)
);
$recipientHistories = MedicalHistoryResource::collection(
$this->medicalHistoryService->getRecipientHistories($dateRange, $department->rf_mis_department_id)
);
$dischargedHistories = MedicalHistoryResource::collection(
$this->medicalHistoryService->getDischargedHistories($dateRange, $department->rf_mis_department_id)
);
$deceasedHistories = MedicalHistoryResource::collection(
$this->medicalHistoryService->getDeceasedHistories($dateRange, $department->rf_mis_department_id)
);
$transferredHistories = MedicalHistoryResource::collection(
$this->medicalHistoryService->getTransferredHistories($dateRange, $department->rf_mis_department_id)
);
}
return Inertia::render('Report/Index', [
'inDepartmentHistories' => $inDepartmentHistories,
'plannedHistories' => $plannedHistories,
'emergencyHistories' => $emergencyHistories,
'recipientHistories' => $recipientHistories,
'dischargedHistories' => $dischargedHistories,
'deceasedHistories' => $deceasedHistories,
'transferredHistories' => $transferredHistories,
'dates' => [
$dateRange->startDate->getTimestampMs(),
$dateRange->endDate->getTimestampMs(),
]
]);
}
/**
* Сохранение отчета от роли мед. сестра
* @return \Illuminate\Http\RedirectResponse
*/
public function store(Request $request)
{
$user = auth()->user();
$dateRange = $this->dateRangeService->getDateRangeFromRequest($request, $user);
$report = $this->dutyReportService->saveReport($dateRange);
$this->dutyReportService->saveSnapshot($dateRange, $report);
return redirect()->back();
}
}

View File

@@ -0,0 +1,22 @@
<?php
namespace App\Http\Resources;
use Illuminate\Http\Request;
use Illuminate\Http\Resources\Json\JsonResource;
class MedicalHistoryResource extends JsonResource
{
/**
* Transform the resource into an array.
*
* @return array<string, mixed>
*/
public function toArray(Request $request): array
{
return [
...$this->resource->toArray(),
'admitted_today' => $this->latestMigration->admittedInCurrent
];
}
}

View File

@@ -182,7 +182,7 @@ class SnapshotPatientSource
}
return MedicalHistory::query()
->whereIn('original_id', $historyIds)
->whereIn('id', $historyIds)
->with(['operations'])
->get()
->mapWithKeys(function (MedicalHistory $history) {

View File

@@ -4,6 +4,7 @@ namespace App\Models;
use App\Services\DateRange;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Carbon;
use Illuminate\Support\Facades\DB;
class MigrationPatient extends MaterializedViewModel
@@ -11,6 +12,14 @@ class MigrationPatient extends MaterializedViewModel
protected $table = 'mv_migrationpatient_details';
protected $primaryKey = 'id';
protected $casts = [
'birth_date' => 'date:Y-m-d',
'recipient_date' => 'datetime:Y-m-d H:i:s',
'extract_date' => 'datetime:Y-m-d H:i:s',
'death_date' => 'datetime:Y-m-d H:i:s',
'male' => 'boolean',
];
public function medicalHistory()
{
return $this->belongsTo(MedicalHistory::class, 'medical_history_id', 'id');
@@ -18,7 +27,8 @@ class MigrationPatient extends MaterializedViewModel
public function operations()
{
return $this->hasMany(SurgicalOperation::class, 'migration_patient_id', 'id');
return $this->hasMany(SurgicalOperation::class, 'migration_patient_id', 'id')
->orderBy('end_date', 'desc');
}
// Пересечение с отчетным периодом
@@ -40,24 +50,6 @@ class MigrationPatient extends MaterializedViewModel
return $query->whereIn('stationar_branch_id', $branchIds);
}
// Добавляет вычисляемый столбец `category` (только для отображения)
public function scopeWithCategory($query, string $from, string $to)
{
$sql = "CASE
WHEN ingoing_date BETWEEN ? AND ? THEN 'admitted'
WHEN out_date BETWEEN ? AND ? THEN
CASE
WHEN death_date IS NOT NULL AND death_date BETWEEN ? AND ? THEN 'deceased'
WHEN stat_cure_result_id IN (3,4,7) THEN 'transferred'
ELSE 'discharged'
END
WHEN ingoing_date < ? AND (out_date IS NULL OR out_date > ?) THEN 'current'
ELSE 'historical'
END as category";
return $query->selectRaw($sql, [$from, $to, $from, $to, $from, $to, $to, $to]);
}
// Быстрые фильтры по статусам (используют индексы MV, а не computed column)
public function scopeAdmitted($query, string $from, string $to)
{
@@ -89,7 +81,29 @@ class MigrationPatient extends MaterializedViewModel
public function scopeCurrent($query, DateRange $dateRange)
{
return $query->where('is_actually_current', true);
return $query->whereNull('out_date')
->whereNotNull('medical_history_id')
->where('ingoing_date', '<', $dateRange->startSql())
->wherehas('medicalHistory', function ($query) use ($dateRange) {
$query->whereNull('extract_date');
});
}
public function scopeCurrentOrAdmitted($query, DateRange $dateRange)
{
return $query->where(function ($q) use ($dateRange) {
// Вариант А: Пациент уже лежит (текущий)
$q->whereNull('out_date')
->whereNotNull('medical_history_id')
->where('ingoing_date', '<', $dateRange->startSql())
->wherehas('medicalHistory', function ($query) use ($dateRange) {
$query->whereNull('extract_date');
}); // опционально: поступил не раньше 2 лет назад
})
->orWhere(function ($q) use ($dateRange) {
$q->where('ingoing_date', '<=', $dateRange->endSql())
->where('ingoing_date', '>', $dateRange->startSql());
});
}
public function scopeCurrentMigration($query, $historyId, $departmentId)
@@ -99,4 +113,23 @@ class MigrationPatient extends MaterializedViewModel
->orderBy('ingoing_date', 'desc')
->limit(1)->first();
}
public function getAdmittedInCurrentAttribute(): bool
{
// Получаем дату поступления из последнего движения
$ingoing = $this->ingoing_date;
if (!$ingoing) {
return false;
}
$ingoingLocal = Carbon::parse($ingoing)->setTimezone(config('app.timezone', 'Europe/Moscow'));
$now = Carbon::now(config('app.timezone', 'Europe/Moscow'));
// Окно смены: вчера 09:00 → сегодня 09:00
$shiftStart = $now->copy()->subDay()->setTime(9, 0);
$shiftEnd = $now->copy()->setTime(9, 0);
return $ingoingLocal->between($shiftStart, $shiftEnd);
}
}

42
app/Models/ReportDuty.php Normal file
View File

@@ -0,0 +1,42 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class ReportDuty extends Model
{
protected $fillable = [
'report_date',
'sent_at',
'period_type',
'period_start',
'period_end',
'status_id',
'rf_lpudoctor_id',
'rf_department_id',
'rf_user_id',
];
protected $casts = [
'report_date' => 'date:Y-m-d',
'sent_at' => 'datetime:Y-m-d H:i:s',
'period_start' => 'datetime:Y-m-d H:i:s',
'period_end' => 'datetime:Y-m-d H:i:s',
];
public function department()
{
return $this->belongsTo(Department::class, 'rf_department_id', 'department_id');
}
public function patients()
{
return $this->hasMany(ReportNursePatient::class, 'report_nurse_id');
}
public function status()
{
return $this->belongsTo(ReportStatus::class);
}
}

View File

@@ -0,0 +1,108 @@
<?php
namespace App\Models;
use App\Services\DateRange;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Facades\DB;
class ReportDutyMigrationPatient extends Model
{
protected $fillable = [
'medical_history_id',
'ingoing_date',
'out_date',
'diagnosis_id',
'diagnosis_code',
'diagnosis_name',
'interrupted_event_id',
'stationar_branch_id',
'department_id',
'visit_result_id',
'stat_cure_result_id',
'user_id',
'mis_user_id',
'comment',
];
protected $casts = [
'ingoing_date' => 'datetime:Y-m-d H:i:s',
'out_date' => 'datetime:Y-m-d H:i:s',
];
public function medicalHistory()
{
return $this->belongsTo(ReportNursePatient::class, 'medical_history_id', 'id');
}
public function operations()
{
return $this->hasMany(SurgicalOperation::class, 'migration_patient_id', 'id');
}
// Пересечение с отчетным периодом
public function scopeDateRange($query, string $from, string $to)
{
return $query->where('ingoing_date', '<=', $to)
->where(function ($q) use ($from) {
$q->whereNull('out_date')->orWhere('out_date', '>=', $from);
});
}
// Фильтр по подразделению (получает ID отделений)
public function scopeDepartment($query, int $departmentId)
{
$branchIds = DB::table('stt_stationarbranch')
->where('rf_DepartmentID', $departmentId)
->pluck('StationarBranchID');
return $query->whereIn('stationar_branch_id', $branchIds);
}
// Быстрые фильтры по статусам (используют индексы MV, а не computed column)
public function scopeAdmitted($query, string $from, string $to)
{
return $query->where('ingoing_date', '>', $from)
->where('ingoing_date', '<=', $to);
}
public function scopeDischarged($query, string $from, string $to)
{
return $query->where('out_date', '>', $from)
->where('out_date', '<=', $to)
->whereNotIn('visit_result_id', [3, 4, 5, 6])
->whereNull('death_date'); // умершие не считаются "выбывшими домой"
}
public function scopeTransferred($query, string $from, string $to)
{
return $query->where('out_date', '>', $from)
->where('out_date', '<=', $to)
->whereIn('visit_result_id', [3, 4]);
}
public function scopeDeceased($query, string $from, string $to)
{
return $query->whereNotNull('death_date')
->where('death_date', '>', $from)
->where('death_date', '<=', $to);
}
public function scopeCurrent($query, DateRange $dateRange)
{
return $query->whereNull('out_date')
->whereNotNull('medical_history_id')
->where('ingoing_date', '<', $dateRange->startSql())
->whereHas('medicalHistory', function ($query) use ($dateRange) {
$query->whereNull('extract_date');
});
}
public function scopeCurrentMigration($query, $historyId, $departmentId)
{
return $query->where('medical_history_id', $historyId)
->department($departmentId)
->orderBy('ingoing_date', 'desc')
->limit(1)->first();
}
}

View File

@@ -0,0 +1,61 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class ReportDutyPatient extends Model
{
protected $fillable = [
'report_duty_id',
'source_type',
'original_id',
'medical_card_number',
'full_name',
'birth_date',
'recipient_date',
'extract_date',
'death_date',
'male',
'urgency_id',
'hospital_result_id',
'visit_result_id',
'comment',
'user_id'
];
protected $casts = [
'birth_date' => 'date:Y-m-d',
'recipient_date' => 'datetime:Y-m-d H:i:s',
'extract_date' => 'datetime:Y-m-d H:i:s',
'death_date' => 'datetime:Y-m-d H:i:s',
'male' => 'boolean',
];
public function migrations(): \Illuminate\Database\Eloquent\Relations\HasMany
{
return $this->hasMany(ReportDutyMigrationPatient::class, 'medical_history_id', 'id');
}
public function operations(): \Illuminate\Database\Eloquent\Relations\HasMany
{
return $this->hasMany(SurgicalOperation::class, 'medical_history_id', 'id');
}
public function latestMigration()
{
return $this->hasOne(ReportDutyMigrationPatient::class, 'medical_history_id', 'id')
->latest('ingoing_date');
}
public function operationsInDepartment($query, $departmentId)
{
return $this->operations()->where('department_id', $departmentId);
}
// Скоупы
public function scopeUrgency($query, $typeId) // 1 = Экстренно, 2 = Планово
{
return $query->where('urgency_id', $typeId);
}
}

View File

@@ -0,0 +1,116 @@
<?php
namespace App\Services;
use App\Models\ReportDutyPatient;
use Illuminate\Support\Carbon;
class DutyMedicalHistoryService
{
public function getHistories(DateRange $dateRange, int $departmentId)
{
$query = ReportDutyPatient::query();
$query->where('recipient_date', '>=', $dateRange->startSql())
->where('recipient_date', '<', $dateRange->endSql())
// 1. Оставляем только тех пациентов, у которых БЫЛО движение в этом отделении
->whereHas('latestMigration', fn($q) => $q->where('department_id', $departmentId))
// 2. Загружаем ТОЛЬКО последнее движение в этом отделении (не все миграции)
->with(['latestMigration' => fn($q) => $q->where('department_id', $departmentId)]);
$result = $query->paginate();
return $result;
}
public function getUrgencyHistory(DateRange $dateRange, int $departmentId, int $urgencyId)
{
$query = ReportDutyPatient::query();
$query->where('recipient_date', '>=', $dateRange->startSql())
->where('recipient_date', '<', $dateRange->endSql())
->urgency($urgencyId)
->whereHas('migrations', function ($m) use ($departmentId) {
$m->where('department_id', $departmentId);
})
->with([
'migrations' => fn ($m) => $m->where('department_id', $departmentId),
'migrations.operations'
]);
$result = $query->paginate();
return $result;
}
public function getDepartmentHistories(DateRange $dateRange, int $departmentId)
{
return ReportDutyPatient::query()
->whereHas('migrations', function ($q) use ($departmentId, $dateRange) {
$q->department($departmentId)->current($dateRange);
})
->with(['latestMigration' => function ($q) use ($departmentId, $dateRange) {
$q->department($departmentId)->current($dateRange); // подгружаем только отфильтрованные движения
}])
->get()
// Сортировка по дате поступления в отделение (поле дочерней таблицы)
->sortByDesc(fn ($mh) => $mh->latestMigration->ingoing_date ?? $mh->recipient_date)
->values();
}
/**
* Получить карты поступившие сегодня
* @param DateRange $dateRange
* @param int $departmentId
*/
public function getRecipientHistories(DateRange $dateRange, int $departmentId)
{
$now = Carbon::now();
return ReportDutyPatient::query()
->whereHas('migrations', function ($q) use ($departmentId, $dateRange) {
$q->department($departmentId)->admitted($dateRange->startSql(), $dateRange->endSql());
})
->with(['latestMigration' => function ($q) use ($departmentId) {
$q->department($departmentId);
}])
->get();
}
public function getDischargedHistories(DateRange $dateRange, int $departmentId)
{
return ReportDutyPatient::query()
->whereHas('migrations', function ($q) use ($departmentId, $dateRange) {
$q->department($departmentId)->discharged($dateRange->startSql(), $dateRange->endSql());
})
->with(['latestMigration' => function ($q) use ($departmentId) {
$q->department($departmentId);
}])
->get();
}
public function getDeceasedHistories(DateRange $dateRange, int $departmentId)
{
return ReportDutyPatient::query()
->whereHas('migrations', function ($q) use ($departmentId, $dateRange) {
$q->department($departmentId)->deceased($dateRange->startSql(), $dateRange->endSql());
})
->with(['latestMigration' => function ($q) use ($departmentId) {
$q->department($departmentId);
}])
->get();
}
public function getTransferredHistories(DateRange $dateRange, int $departmentId)
{
return ReportDutyPatient::query()
->whereHas('migrations', function ($q) use ($departmentId, $dateRange) {
$q->department($departmentId)->transferred($dateRange->startSql(), $dateRange->endSql());
})
->with(['latestMigration' => function ($q) use ($departmentId) {
$q->department($departmentId);
}])
->get();
}
}

View File

@@ -0,0 +1,249 @@
<?php
namespace App\Services;
use App\Models\MedicalHistory;
use App\Models\ReportDuty;
use App\Models\ReportNurse;
use App\Models\UnifiedMedicalHistory;
use App\Models\User;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Support\Carbon;
use Illuminate\Support\Facades\DB;
class DutyReportService
{
/**
* Базовый запрос для всех отчётов
* Фильтрует по отделению и периоду, подгружает связи
*/
protected function baseQuery(DateRange $dateRange, int $departmentId): Builder
{
return UnifiedMedicalHistory::query()
->whereHas('migrations', function ($q) use ($departmentId, $dateRange) {
$q->department($departmentId)->dateRange($dateRange->startSql(), $dateRange->endSql());
})
->with(['latestMigration' => function ($q) use ($departmentId, $dateRange) {
$q->department($departmentId)->dateRange($dateRange->startSql(), $dateRange->endSql());
}]);
}
/**
* Сохранить отчет
*/
public function saveReport(DateRange $dateRange, ?int $userId = null, ?int $lpuDoctorId = null, ?int $departmentId = null)
{
$user = $userId ? User::find($userId) : auth()->user();
$lpuDoctorId = $lpuDoctorId ?? $user->rf_lpudoctor_id;
$departmentId = $departmentId ?? $user->rf_department_id;
$data = [
'report_date' => Carbon::now()->format('Y-m-d'),
'sent_at' => Carbon::now()->format('Y-m-d H:i:s'),
'period_type' => 'day',
'period_start' => $dateRange->startSql(),
'period_end' => $dateRange->endSql(),
'status_id' => 2, // опубликован
'rf_lpudoctor_id' => $lpuDoctorId,
'rf_department_id' => $departmentId,
'rf_user_id' => $user->id,
];
$report = ReportDuty::updateOrCreate(
[
'report_date' => $data['report_date'], 'period_start' => $data['period_start'],
'period_end' => $data['period_end']
],
$data
);
return $report;
}
/**
* Сохранить снимок пациентов за период
*/
public function saveSnapshot(DateRange $dateRange, ReportNurse $reportNurse, ?int $departmentId = null, ?int $userId = null): array
{
$departmentId = $departmentId ?? $reportNurse->department->rf_mis_department_id;
$userId = $userId ?? $reportNurse->rf_user_id;
$startYear = Carbon::now()->startOfYear()->format('Y-m-d');
$query = MedicalHistory::query()
// Фильтруем движения по отделению + пересечение дат
->whereHas('migrations', function ($q) use ($departmentId, $dateRange, $startYear) {
$q->where('department_id', $departmentId)
// пребывание пересекается с отчётным периодом
->where('ingoing_date', '<=', $dateRange->endSql())
->where('ingoing_date', '>=', $startYear)
->where(function ($sub) use ($dateRange) {
$sub->whereNull('out_date')
->orWhere('out_date', '>=', $dateRange->startSql())
->where('out_date', '<=', $dateRange->endSql());
});
});
// Получаем данные (chunk для памяти, если пациентов > 1000)
$patients = $query->cursor();
$savedStats = $this->saveReportSnapshot($reportNurse->id, $patients, $userId);
return [
...$savedStats,
'report_date' => $dateRange->startSql(),
'department_id' => $departmentId,
];
}
public function saveReportSnapshot(int $reportDutyId, iterable $patients, int $userId): array
{
if (empty($patients)) {
return ['saved_patients' => 0, 'saved_migrations' => 0];
}
$patientBatch = [];
$migrationBatch = [];
$batchSize = 100;
foreach ($patients as $patient) {
// Подготовка данных пациента
$patientBatch[] = [
'report_nurse_id' => $reportDutyId,
'source_type' => $patient->source_type,
'original_id' => $patient->original_id,
'medical_card_number' => $patient->medical_card_number,
'full_name' => $patient->full_name,
'birth_date' => $patient->birth_date,
'recipient_date' => $patient->recipient_date,
'extract_date' => $patient->extract_date,
'death_date' => $patient->death_date,
'male' => $patient->male,
'urgency_id' => $patient->urgency_id,
'hospital_result_id' => $patient->hospital_result_id,
'visit_result_id' => $patient->visit_result_id,
'comment' => $patient->comment,
'user_id' => $userId,
];
// Подготовка данных миграции (если есть)
if (!empty($patient->migrations)) {
foreach ($patient->migrations as $migration) {
$migrationBatch[] = [
// Временный ключ для связи с пациентом (заполним после первого upsert)
'_temp_key' => [
'report_duty_id' => $reportDutyId,
'source_type' => $patient->source_type,
'original_id' => $patient->original_id,
],
'ingoing_date' => $migration->ingoing_date,
'out_date' => $migration->out_date,
'diagnosis_id' => $migration->diagnosis_id,
'diagnosis_code' => $migration->diagnosis_code,
'diagnosis_name' => $migration->diagnosis_name,
'interrupted_event_id' => $migration->interrupted_event_id,
'stationar_branch_id' => $migration->stationar_branch_id,
'department_id' => $migration->department_id,
'visit_result_id' => $migration->visit_result_id,
'stat_cure_result_id' => $migration->stat_cure_result_id,
'user_id' => $migration->user_id,
'mis_user_id' => $migration->mis_user_id,
'comment' => $migration->comment,
];
}
}
// Пакетная запись каждые $batchSize записей
if (count($patientBatch) >= $batchSize) {
[$savedP, $savedM] = $this->upsertBatches($reportDutyId, $patientBatch, $migrationBatch);
$patientBatch = [];
$migrationBatch = [];
}
}
// Сохраняем остаток
[$savedP, $savedM] = $this->upsertBatches($reportDutyId, $patientBatch, $migrationBatch);
return ['saved_patients' => $savedP, 'saved_migrations' => $savedM];
}
/**
* Вспомогательный метод: выполняет upsert для пациентов и миграций
*/
private function upsertBatches(int $reportDutyId, array $patientBatch, array $migrationBatch): array
{
if (empty($patientBatch)) {
return [0, 0];
}
$savedPatients = 0;
$savedMigrations = 0;
DB::transaction(function () use ($reportDutyId, $patientBatch, $migrationBatch, &$savedPatients, &$savedMigrations) {
// UPSERT пациентов
$patientUniqueBy = ['report_duty_id', 'source_type', 'original_id'];
$patientUpdateColumns = array_diff(array_keys($patientBatch[0]), $patientUniqueBy);
DB::table('report_nurse_patients')->upsert(
$patientBatch,
$patientUniqueBy,
$patientUpdateColumns
);
$savedPatients = count($patientBatch);
// Получаем ID сохранённых пациентов для связи с миграциями
if (!empty($migrationBatch)) {
// Извлекаем уникальные ключи для поиска
$tempKeys = array_map(fn($m) => $m['_temp_key'], $migrationBatch);
// Получаем реальные ID из БД
$patientIds = DB::table('report_duty_patients')
->whereIn('report_duty_id', [$reportDutyId])
->get()
->pluck('id', 'original_id') // key=original_id, value=id
->toArray();
// Формируем финальный массив миграций с реальными medical_history_id
$finalMigrations = [];
foreach ($migrationBatch as $m) {
$tempKey = $m['_temp_key'];
$originalId = $tempKey['original_id'];
if (isset($patientIds[$originalId])) {
$finalMigrations[] = [
'medical_history_id' => $patientIds[$originalId], // Реальный ID
'ingoing_date' => $m['ingoing_date'],
'out_date' => $m['out_date'],
'diagnosis_id' => $m['diagnosis_id'],
'diagnosis_code' => $m['diagnosis_code'],
'diagnosis_name' => $m['diagnosis_name'],
'interrupted_event_id' => $m['interrupted_event_id'],
'stationar_branch_id' => $m['stationar_branch_id'],
'department_id' => $m['department_id'],
'visit_result_id' => $m['visit_result_id'],
'stat_cure_result_id' => $m['stat_cure_result_id'],
'user_id' => $m['user_id'],
'mis_user_id' => $m['mis_user_id'],
'comment' => $m['comment'],
];
}
}
if (!empty($finalMigrations)) {
// UPSERT миграций
$migrationUniqueBy = ['medical_history_id', 'ingoing_date'];
$migrationUpdateColumns = array_diff(array_keys($finalMigrations[0]), $migrationUniqueBy);
DB::table('report_duty_migration_patients')->upsert(
$finalMigrations,
$migrationUniqueBy,
$migrationUpdateColumns
);
$savedMigrations = count($finalMigrations);
}
}
});
return [$savedPatients, $savedMigrations];
}
}

View File

@@ -49,11 +49,43 @@ class MedicalHistoryService
{
return MedicalHistory::query()
->whereHas('migrations', function ($q) use ($departmentId, $dateRange) {
$q->department($departmentId)->current($dateRange);
$q->department($departmentId)->currentOrAdmitted($dateRange);
})
->with(['latestMigration' => function ($q) use ($departmentId, $dateRange) {
$q->department($departmentId)->current($dateRange); // подгружаем только отфильтрованные движения
}])
$q->department($departmentId)->currentOrAdmitted($dateRange)->latest('ingoing_date'); // подгружаем только отфильтрованные движения
}, 'latestMigration.operations'])
->get()
// Сортировка по дате поступления в отделение (поле дочерней таблицы)
->sortByDesc(fn ($mh) => $mh->latestMigration->ingoing_date ?? $mh->recipient_date)
->values();
}
public function getPlannedHistories(DateRange $dateRange, int $departmentId)
{
return MedicalHistory::query()
->whereHas('migrations', function ($q) use ($departmentId, $dateRange) {
$q->department($departmentId)->currentOrAdmitted($dateRange);
})
->with(['latestMigration' => function ($q) use ($departmentId, $dateRange) {
$q->department($departmentId)->currentOrAdmitted($dateRange)
->latest('ingoing_date'); // подгружаем только отфильтрованные движения
}, 'latestMigration.operations'])
->urgency(1)
->get()
// Сортировка по дате поступления в отделение (поле дочерней таблицы)
->sortByDesc(fn ($mh) => $mh->latestMigration->ingoing_date ?? $mh->recipient_date)
->values();
}
public function getEmergencyHistories(DateRange $dateRange, int $departmentId)
{
return MedicalHistory::query()
->whereHas('migrations', function ($q) use ($departmentId, $dateRange) {
$q->department($departmentId)->currentOrAdmitted($dateRange);
})
->with(['latestMigration' => function ($q) use ($departmentId, $dateRange) {
$q->department($departmentId)->currentOrAdmitted($dateRange)->latest('ingoing_date'); // подгружаем только отфильтрованные движения
}, 'latestMigration.operations'])
->urgency(2)
->get()
// Сортировка по дате поступления в отделение (поле дочерней таблицы)
->sortByDesc(fn ($mh) => $mh->latestMigration->ingoing_date ?? $mh->recipient_date)
@@ -75,7 +107,7 @@ class MedicalHistoryService
})
->with(['latestMigration' => function ($q) use ($departmentId) {
$q->department($departmentId);
}])
}, 'latestMigration.operations'])
->get();
}
@@ -87,7 +119,7 @@ class MedicalHistoryService
})
->with(['latestMigration' => function ($q) use ($departmentId) {
$q->department($departmentId);
}])
}, 'latestMigration.operations'])
->get();
}
@@ -99,7 +131,7 @@ class MedicalHistoryService
})
->with(['latestMigration' => function ($q) use ($departmentId) {
$q->department($departmentId);
}])
}, 'latestMigration.operations'])
->get();
}
@@ -111,7 +143,7 @@ class MedicalHistoryService
})
->with(['latestMigration' => function ($q) use ($departmentId) {
$q->department($departmentId);
}])
}, 'latestMigration.operations'])
->get();
}
}