From cb43c74a7265cb9c05aaeae463981d17d779a1df Mon Sep 17 00:00:00 2001 From: brusnitsyn Date: Thu, 22 Jan 2026 17:58:27 +0900 Subject: [PATCH] =?UTF-8?q?*=20=D0=B4=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB=D0=B5?= =?UTF-8?q?=D0=BD=D1=8B=20=D0=BE=D0=BF=D0=B5=D1=80=D0=B0=D1=86=D0=B8=D0=B8?= =?UTF-8?q?=20=D0=B8=20=D1=83=D1=81=D0=BB=D1=83=D0=B3=D0=B8=20=D0=BE=D0=BF?= =?UTF-8?q?=D0=B5=D1=80=D0=B0=D1=86=D0=B8=D0=B9=20*=20=D0=B4=D0=BE=D0=B1?= =?UTF-8?q?=D0=B0=D0=B2=D0=BB=D0=B5=D0=BD=D0=B0=20=D0=B2=D1=8B=D0=B1=D0=BE?= =?UTF-8?q?=D1=80=D0=BA=D0=B0=20=D0=B8=20=D0=BF=D0=BE=D0=B4=D1=81=D1=87?= =?UTF-8?q?=D0=B5=D1=82=20=D0=BF=D0=BE=20=D0=B4=D0=B0=D1=82=D0=B0=D0=BC=20?= =?UTF-8?q?=D0=B4=D0=BB=D1=8F=20=D1=80=D0=BE=D0=BB=D0=B8=20=D0=B7=D0=B0?= =?UTF-8?q?=D0=B2.=20*=20=D0=BF=D0=B5=D1=80=D0=B5=D0=BA=D0=BB=D1=8E=D1=87?= =?UTF-8?q?=D0=B0=D1=82=D0=B5=D0=BB=D1=8C=20=D1=80=D0=BE=D0=BB=D0=B5=D0=B9?= =?UTF-8?q?=20*=20=D0=B2=D1=8B=D0=B1=D0=BE=D1=80=20=D0=BE=D1=82=D0=B4?= =?UTF-8?q?=D0=B5=D0=BB=D0=B5=D0=BD=D0=B8=D0=B9=20=D0=B4=D0=BB=D1=8F=20?= =?UTF-8?q?=D1=80=D0=BE=D0=BB=D0=B8=20=D0=B7=D0=B0=D0=B2.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/Http/Controllers/Api/ReportController.php | 463 +++++++++++++++--- app/Http/Controllers/AuthController.php | 19 + app/Http/Middleware/HandleInertiaRequests.php | 1 + .../Mis/FormattedPatientResource.php | 10 + app/Models/MisMedicalHistory.php | 16 + app/Models/MisMigrationPatient.php | 42 ++ app/Models/MisServiceMedical.php | 16 + app/Models/MisSurgicalOperation.php | 16 + app/Models/ObservationPatient.php | 1 + app/Models/UnwantedEvent.php | 15 + app/Models/User.php | 14 +- ...t_column_in_observation_patients_table.php | 28 ++ ..._column_current_role_id_in_users_table.php | 28 ++ ...22_152242_create_unwanted_events_table.php | 29 ++ resources/js/Components/DepartmentSelect.vue | 22 + resources/js/Components/ReportSelectDate.vue | 4 +- resources/js/Layouts/Components/AppHeader.vue | 19 +- .../js/Layouts/Components/AppUserButton.vue | 49 +- .../js/Pages/Report/Components/ReportForm.vue | 2 +- .../Pages/Report/Components/ReportHeader.vue | 51 +- .../Pages/Report/Components/ReportSection.vue | 9 +- .../Report/Components/ReportSectionHeader.vue | 18 +- .../Report/Components/ReportSectionItem.vue | 89 +++- .../Report/Components/UnwantedEventModal.vue | 50 ++ resources/js/Pages/Report/Index.vue | 13 +- resources/js/Stores/auth.js | 33 +- resources/js/Stores/report.js | 42 +- routes/web.php | 5 + 28 files changed, 961 insertions(+), 143 deletions(-) create mode 100644 app/Models/MisServiceMedical.php create mode 100644 app/Models/MisSurgicalOperation.php create mode 100644 app/Models/UnwantedEvent.php create mode 100644 database/migrations/2026_01_21_170206_add_comment_column_in_observation_patients_table.php create mode 100644 database/migrations/2026_01_22_142054_add_column_current_role_id_in_users_table.php create mode 100644 database/migrations/2026_01_22_152242_create_unwanted_events_table.php create mode 100644 resources/js/Components/DepartmentSelect.vue create mode 100644 resources/js/Pages/Report/Components/UnwantedEventModal.vue diff --git a/app/Http/Controllers/Api/ReportController.php b/app/Http/Controllers/Api/ReportController.php index 9bc96c1..487f0e6 100644 --- a/app/Http/Controllers/Api/ReportController.php +++ b/app/Http/Controllers/Api/ReportController.php @@ -7,13 +7,16 @@ use App\Http\Resources\Mis\FormattedPatientResource; use App\Models\MetrikaGroup; use App\Models\MetrikaResult; use App\Models\MisMedicalHistory; +use App\Models\MisMigrationPatient; use App\Models\MisStationarBranch; use App\Models\ObservationPatient; use App\Models\Report; +use App\Models\UnwantedEvent; use Illuminate\Http\Request; use Illuminate\Support\Carbon; use Illuminate\Support\Facades\Auth; use Illuminate\Support\Facades\DB; +use Illuminate\Support\Facades\Session; use Illuminate\Support\Str; use Inertia\Inertia; @@ -21,9 +24,26 @@ class ReportController extends Controller { public function index(Request $request) { - $user = $request->user(); + $user = Auth::user(); $department = $user->department; + $startDateCarbon = Carbon::now()->firstOfMonth(); + $startDate = $request->query('startAt', $startDateCarbon->format('Y-m-d')); + $endDateCarbon = Carbon::now(); + $endDate = $request->query('endAt', $endDateCarbon->format('Y-m-d')); + + $doctorStartDate = Carbon::now()->addDays(-1)->format('Y-m-d'); + $doctorEndDate = Carbon::now()->format('Y-m-d'); + + if (is_numeric($startDate)) { + $startDateCarbon = Carbon::createFromTimestampMs($startDate); + $startDate = Carbon::createFromTimestampMs($startDate)->setTimezone('Asia/Yakutsk')->format('Y-m-d'); + } + if (is_numeric($endDate)) { + $endDateCarbon = Carbon::createFromTimestampMs($endDate); + $endDate = Carbon::createFromTimestampMs($endDate)->setTimezone('Asia/Yakutsk')->format('Y-m-d'); + } + $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') @@ -35,10 +55,103 @@ class ReportController extends Controller $metrikaGroup = MetrikaGroup::whereMetrikaGroupId(2)->first(); $metrikaItems = $metrikaGroup->metrikaItems; + $misDepartmentId = $request->user()->department->rf_mis_department_id; + + $branchId = MisStationarBranch::where('rf_DepartmentID', $misDepartmentId) + ->value('StationarBranchID'); + if ($user->isHeadOfDepartment()) + { + $medicalHistoryIds = MisMigrationPatient::whereInDepartment($branchId) + ->pluck('rf_MedicalHistoryID') + ->unique() + ->toArray(); + + $extractedMedicalHistoryIds = MisMigrationPatient::extractedToday($branchId, $startDate, $endDate) + ->pluck('rf_MedicalHistoryID') + ->unique() + ->toArray(); + + $recipientCount = MisMedicalHistory::whereIn('MedicalHistoryID', $medicalHistoryIds) + ->when($user->isHeadOfDepartment(), function($query) use ($startDate, $endDate) { + return $query->whereBetween('DateRecipient', [$startDate, $endDate]); + }) + ->when(!$user->isHeadOfDepartment(), function($query) use ($doctorStartDate, $doctorEndDate) { + return $query->whereBetween('DateRecipient', [$doctorStartDate, $doctorEndDate]); + }) + ->orderBy('DateRecipient', 'DESC') + ->count(); + + $extractedCount = MisMedicalHistory::whereIn('MedicalHistoryID', $extractedMedicalHistoryIds) + ->orderBy('DateRecipient', 'DESC') + ->count(); + + $recipientIds = MisMedicalHistory::whereIn('MedicalHistoryID', $medicalHistoryIds) + ->when($doctorStartDate, function($query) use ($doctorStartDate, $doctorEndDate) { + return $query->whereBetween('DateRecipient', [$doctorStartDate, $doctorEndDate]); + }) + ->orderBy('DateRecipient', 'DESC') + ->pluck('MedicalHistoryID') + ->values(); + + $currentCount = MisMedicalHistory::whereIn('MedicalHistoryID', $medicalHistoryIds) + ->currentlyHospitalized() + ->orderBy('DateRecipient', 'DESC') + ->count(); + } else { + $medicalHistoryIds = MisMigrationPatient::currentlyInTreatment($branchId) + ->pluck('rf_MedicalHistoryID') + ->unique() + ->toArray(); + + $extractedMedicalHistoryIds = MisMigrationPatient::extractedToday($branchId) + ->pluck('rf_MedicalHistoryID') + ->unique() + ->toArray(); + + $recipientCount = MisMedicalHistory::whereIn('MedicalHistoryID', $medicalHistoryIds) + ->when($user->isHeadOfDepartment(), function($query) use ($startDate, $endDate) { + return $query->whereBetween('DateRecipient', [$startDate, $endDate]); + }) + ->when(!$user->isHeadOfDepartment(), function($query) use ($doctorStartDate, $doctorEndDate) { + return $query->whereBetween('DateRecipient', [$doctorStartDate, $doctorEndDate]); + }) + ->orderBy('DateRecipient', 'DESC') + ->count(); + + $extractedCount = MisMedicalHistory::whereIn('MedicalHistoryID', $extractedMedicalHistoryIds) + ->orderBy('DateRecipient', 'DESC') + ->count(); + + $recipientIds = MisMedicalHistory::whereIn('MedicalHistoryID', $medicalHistoryIds) + ->when($user->isHeadOfDepartment(), function($query) use ($startDate, $endDate) { + return $query->whereBetween('DateRecipient', [$startDate, $endDate]); + }) + ->when(!$user->isHeadOfDepartment(), function($query) use ($doctorStartDate, $doctorEndDate) { + return $query->whereBetween('DateRecipient', [$doctorStartDate, $doctorEndDate]); + }) + ->orderBy('DateRecipient', 'DESC') + ->pluck('MedicalHistoryID') + ->values(); + + $currentCount = MisMedicalHistory::whereIn('MedicalHistoryID', $medicalHistoryIds) + ->currentlyHospitalized() + ->orderBy('DateRecipient', 'DESC') + ->count(); + } + + return response()->json([ 'department' => [ 'beds' => $beds, 'percentLoadedBeds' => $percentLoadedBeds, + 'recipientCount' => $recipientCount, + 'extractCount' => $extractedCount, + 'currentCount' => $currentCount, + 'recipientIds' => $recipientIds + ], + 'dates' => [ + 'startAt' => $startDateCarbon->getTimestampMs(), + 'endAt' => $endDateCarbon->getTimestampMs() ], 'metrikaItems' => $metrikaItems ]); @@ -50,6 +163,7 @@ class ReportController extends Controller 'metrics' => 'required', 'observationPatients' => 'nullable', 'departmentId' => 'required|integer', + 'unwantedEvent' => 'nullable' ]); $metrics = $data['metrics']; @@ -74,6 +188,13 @@ class ReportController extends Controller 'sent_at' => now() ]); + if (in_array('unwantedEvent', $data)) { + $unwantedEvent = UnwantedEvent::create([ + 'rf_report_id' => $report->id, + 'comment' => $data['unwantedEvent']['comment'] ?? '', + ]); + } + foreach ($metriks as $metrika) { $metrika->rf_report_id = $report->report_id; $metrika->save(); @@ -97,59 +218,215 @@ class ReportController extends Controller public function getPatients(Request $request) { + $user = Auth::user(); $data = $request->validate([ 'status' => 'required|string', // plan emergency + 'startAt' => 'nullable', + 'endAt' => 'nullable', ]); $status = $data['status']; - $startDate = Carbon::now()->addDays(-1)->format('Y-m-d'); - $endDate = Carbon::now()->format('Y-m-d'); + $startDateCarbon = Carbon::now()->firstOfMonth(); + $startDate = $data['startAt'] ?? $startDateCarbon->format('Y-m-d'); + $endDateCarbon = Carbon::now(); + $endDate = $data['endAt'] ?? $startDateCarbon->format('Y-m-d'); + + $doctorStartDate = Carbon::now()->addDays(-1)->format('Y-m-d'); + $doctorEndDate = Carbon::now()->format('Y-m-d'); + + if (is_numeric($startDate)) { + $startDateCarbon = Carbon::createFromTimestampMs($startDate); + $startDate = Carbon::createFromTimestampMs($startDate)->setTimezone('Asia/Yakutsk')->format('Y-m-d'); + } + if (is_numeric($endDate)) { + $endDateCarbon = Carbon::createFromTimestampMs($endDate); + $endDate = Carbon::createFromTimestampMs($endDate)->setTimezone('Asia/Yakutsk')->format('Y-m-d'); + } $model = new MisMedicalHistory(); $misDepartmentId = $request->user()->department->rf_mis_department_id; + $userDepartmentId = $request->user()->department->department_id; $misStationarBranchId = MisStationarBranch::where('rf_DepartmentID', $misDepartmentId)->first()->StationarBranchID; - if ($status === 'plan') { - $patients = MisMedicalHistory::select( - [ - ...$model->getFillable(), - DB::raw('ROW_NUMBER() OVER (ORDER BY "DateRecipient" DESC) as num') - ]) - ->plan() - ->inDepartment($misDepartmentId, $startDate, $endDate) - ->orderBy('DateRecipient', 'DESC') - ->get() - ->map(function ($item, $index) { - $item->num = $index + 1; - return $item; - });; - } else if ($status === 'emergency') { - $patients = MisMedicalHistory::select( - [ - ...$model->getFillable(), - DB::raw('ROW_NUMBER() OVER (ORDER BY "DateRecipient" DESC) as num') - ]) - ->emergency() - ->inDepartment($misDepartmentId, $startDate, $endDate) - ->orderBy('DateRecipient', 'DESC') - ->get() - ->map(function ($item, $index) { - $item->num = $index + 1; - return $item; - }); - } else if ($status === 'observation') { - $patients = ObservationPatient::with(['history']) - ->where('rf_department_id', $misDepartmentId) - ->history; - } else if ($status === 'deceased') { - $patients = MisMedicalHistory::select(...$model->getFillable()) - ->deceased() - ->inDepartment($misDepartmentId, $startDate, $endDate) - ->get() - ->map(function ($item, $index) { - $item->num = $index + 1; - return $item; - }); + + if ($user->isHeadOfDepartment()) { + if ($status === 'plan') { + // Сначала получаем ID локально + $branchId = MisStationarBranch::where('rf_DepartmentID', $misDepartmentId) + ->value('StationarBranchID'); + + if (!$branchId) { + return collect(); + } + + $medicalHistoryIds = MisMigrationPatient::whereInDepartment($branchId) + ->when($startDate && $endDate, function($query) use ($startDate, $endDate) { + return $query->whereBetween('DateIngoing', [$startDate, $endDate]); + }) + ->pluck('rf_MedicalHistoryID') + ->unique() + ->toArray(); + + if (empty($medicalHistoryIds)) { + return collect(); + } + + // Получаем истории + $patients = MisMedicalHistory::select($model->getFillable()) + ->plan() + ->whereIn('MedicalHistoryID', $medicalHistoryIds) + ->orderBy('DateRecipient', 'DESC') + ->get() + ->map(function ($item, $index) use ($misStationarBranchId) { + $item->num = $index + 1; + $item->misStationarBranchId = $misStationarBranchId; + return $item; + }); + } else if ($status === 'emergency') { + // Сначала получаем ID локально + $branchId = MisStationarBranch::where('rf_DepartmentID', $misDepartmentId) + ->value('StationarBranchID'); + + if (!$branchId) { + return collect(); + } + + $medicalHistoryIds = MisMigrationPatient::whereInDepartment($branchId) + ->when($startDate && $endDate, function($query) use ($startDate, $endDate) { + return $query->whereBetween('DateIngoing', [$startDate, $endDate]); + }) + ->pluck('rf_MedicalHistoryID') + ->unique() + ->toArray(); + + if (empty($medicalHistoryIds)) { + return collect(); + } + + // Получаем истории + $patients = MisMedicalHistory::select($model->getFillable()) + ->emergency() + ->whereIn('MedicalHistoryID', $medicalHistoryIds) + ->with(['surgicalOperations']) + ->orderBy('DateRecipient', 'DESC') + ->get() + ->map(function ($item, $index) use ($misStationarBranchId) { + $item->num = $index + 1; + $item->misStationarBranchId = $misStationarBranchId; + return $item; + }); + } else if ($status === 'observation') { + $medicalHistoryIds = ObservationPatient::where('rf_department_id', $userDepartmentId) + ->pluck('rf_medicalhistory_id') + ->toArray(); + + $patients = MisMedicalHistory::whereIn('MedicalHistoryID', $medicalHistoryIds) + ->get()->map(function ($item, $index) use ($misStationarBranchId) { + $item->num = $index + 1; + $item->misStationarBranchId = $misStationarBranchId; + return $item; + }); + + } else if ($status === 'deceased') { + $patients = MisMedicalHistory::select(...$model->getFillable()) + ->deceased() + ->inDepartment($misDepartmentId, $startDate, $endDate) + ->get() + ->map(function ($item, $index) { + $item->num = $index + 1; + return $item; + }); + } + } else { + if ($status === 'plan') { + // Сначала получаем ID локально + $branchId = MisStationarBranch::where('rf_DepartmentID', $misDepartmentId) + ->value('StationarBranchID'); + + if (!$branchId) { + return collect(); + } + + $medicalHistoryIds = MisMigrationPatient::currentlyInTreatment($branchId) +// ->when($startDate && $endDate, function($query) use ($startDate, $endDate) { +// return $query->whereBetween('DateIngoing', [$startDate, $endDate]); +// }) + ->pluck('rf_MedicalHistoryID') + ->unique() + ->toArray(); + + if (empty($medicalHistoryIds)) { + return collect(); + } + + // Получаем истории + $patients = MisMedicalHistory::select($model->getFillable()) + ->plan() + ->whereIn('MedicalHistoryID', $medicalHistoryIds) + ->currentlyHospitalized() + ->orderBy('DateRecipient', 'DESC') + ->get() + ->map(function ($item, $index) use ($misStationarBranchId) { + $item->num = $index + 1; + $item->misStationarBranchId = $misStationarBranchId; + return $item; + }); + } else if ($status === 'emergency') { + // Сначала получаем ID локально + $branchId = MisStationarBranch::where('rf_DepartmentID', $misDepartmentId) + ->value('StationarBranchID'); + + if (!$branchId) { + return collect(); + } + + $medicalHistoryIds = MisMigrationPatient::currentlyInTreatment($branchId) +// ->when($startDate && $endDate, function($query) use ($startDate, $endDate) { +// return $query->whereBetween('DateIngoing', [$startDate, $endDate]); +// }) + ->pluck('rf_MedicalHistoryID') + ->unique() + ->toArray(); + + if (empty($medicalHistoryIds)) { + return collect(); + } + + // Получаем истории + $patients = MisMedicalHistory::select($model->getFillable()) + ->emergency() + ->whereIn('MedicalHistoryID', $medicalHistoryIds) + ->currentlyHospitalized() + ->with(['surgicalOperations']) + ->orderBy('DateRecipient', 'DESC') + ->get() + ->map(function ($item, $index) use ($misStationarBranchId) { + $item->num = $index + 1; + $item->misStationarBranchId = $misStationarBranchId; + return $item; + }); + } else if ($status === 'observation') { + $medicalHistoryIds = ObservationPatient::where('rf_department_id', $userDepartmentId) + ->pluck('rf_medicalhistory_id') + ->toArray(); + + $patients = MisMedicalHistory::whereIn('MedicalHistoryID', $medicalHistoryIds) + ->get()->map(function ($item, $index) use ($misStationarBranchId) { + $item->num = $index + 1; + $item->misStationarBranchId = $misStationarBranchId; + return $item; + }); + + } else if ($status === 'deceased') { + $patients = MisMedicalHistory::select(...$model->getFillable()) + ->deceased() + ->inDepartment($misDepartmentId, $startDate, $endDate) + ->get() + ->map(function ($item, $index) { + $item->num = $index + 1; + return $item; + }); + } } $patients->load(['migrations' => function ($query) use ($startDate, $endDate, $misStationarBranchId) { @@ -164,29 +441,97 @@ class ReportController extends Controller public function getPatientsCount(Request $request) { + $user = Auth::user(); $data = $request->validate([ 'status' => 'required|string', // plan emergency + 'startAt' => 'nullable', + 'endAt' => 'nullable', ]); $status = $data['status']; - $startDate = Carbon::now()->addDays(-1)->format('Y-m-d'); - $endDate = Carbon::now()->format('Y-m-d'); + $startDateCarbon = Carbon::now()->firstOfMonth(); + $startDate = $data['startAt'] ?? $startDateCarbon->format('Y-m-d'); + $endDateCarbon = Carbon::now(); + $endDate = $data['endAt'] ?? $endDateCarbon->format('Y-m-d'); + + $doctorStartDate = Carbon::now()->addDays(-1)->format('Y-m-d'); + $doctorEndDate = Carbon::now()->format('Y-m-d'); + + if (is_numeric($startDate)) { + $startDateCarbon = Carbon::createFromTimestampMs($startDate); + $startDate = Carbon::createFromTimestampMs($startDate)->setTimezone('Asia/Yakutsk')->format('Y-m-d'); + } + if (is_numeric($endDate)) { + $endDateCarbon = Carbon::createFromTimestampMs($endDate); + $endDate = Carbon::createFromTimestampMs($endDate)->setTimezone('Asia/Yakutsk')->format('Y-m-d'); + } - $model = new MisMedicalHistory(); $misDepartmentId = $request->user()->department->rf_mis_department_id; - if ($status === 'plan') { - $count = MisMedicalHistory::select($model->getFillable()) - ->plan() - ->inDepartment($misDepartmentId, $startDate, $endDate) - ->orderBy('DateRecipient', 'DESC') - ->count(); - } else if ($status === 'emergency') { - $count = MisMedicalHistory::select($model->getFillable()) - ->emergency() - ->inDepartment($misDepartmentId, $startDate, $endDate) - ->orderBy('DateRecipient', 'DESC') - ->count(); + + // Получаем ID отделения + $branchId = MisStationarBranch::where('rf_DepartmentID', $misDepartmentId) + ->value('StationarBranchID'); + + if (!$branchId) { + return response()->json(0); + } + + if ($user->isHeadOfDepartment()) { + // Получаем ID медицинских историй по миграциям + $medicalHistoryIds = MisMigrationPatient::whereInDepartment($branchId) + ->when($startDate && $endDate, function($query) use ($startDate, $endDate) { + return $query->whereBetween('DateIngoing', [$startDate, $endDate]); + }) + ->pluck('rf_MedicalHistoryID') + ->unique() + ->toArray(); + + if (empty($medicalHistoryIds)) { + return response()->json(0); + } + + // Подсчет в зависимости от статуса + if ($status === 'plan') { + $count = MisMedicalHistory::plan() + ->whereIn('MedicalHistoryID', $medicalHistoryIds) + ->orderBy('DateRecipient', 'DESC') + ->count(); + } else if ($status === 'emergency') { + $count = MisMedicalHistory::emergency() + ->whereIn('MedicalHistoryID', $medicalHistoryIds) + ->orderBy('DateRecipient', 'DESC') + ->count(); + } else { + $count = 0; + } + } else { + // Получаем ID медицинских историй по миграциям + $medicalHistoryIds = MisMigrationPatient::currentlyInTreatment($branchId) + ->pluck('rf_MedicalHistoryID') + ->unique() + ->toArray(); + + if (empty($medicalHistoryIds)) { + return response()->json(0); + } + + // Подсчет в зависимости от статуса + if ($status === 'plan') { + $count = MisMedicalHistory::plan() + ->whereIn('MedicalHistoryID', $medicalHistoryIds) + ->currentlyHospitalized() + ->orderBy('DateRecipient', 'DESC') + ->count(); + } else if ($status === 'emergency') { + $count = MisMedicalHistory::emergency() + ->whereIn('MedicalHistoryID', $medicalHistoryIds) + ->currentlyHospitalized() + ->orderBy('DateRecipient', 'DESC') + ->count(); + } else { + $count = 0; + } } return response()->json($count); diff --git a/app/Http/Controllers/AuthController.php b/app/Http/Controllers/AuthController.php index 08e99ba..06fe039 100644 --- a/app/Http/Controllers/AuthController.php +++ b/app/Http/Controllers/AuthController.php @@ -5,6 +5,7 @@ namespace App\Http\Controllers; use App\Models\User; use Illuminate\Http\Request; use Illuminate\Support\Facades\Auth; +use Illuminate\Support\Facades\Redis; use Illuminate\Support\Facades\Validator; use Inertia\Inertia; @@ -53,4 +54,22 @@ class AuthController extends Controller return Inertia::location(route('start')); } + + public function changeRole(Request $request) + { + $user = Auth::user(); + + if (!$user) return null; + + $data = $request->validate([ + 'role_id' => 'required|integer|exists:roles,role_id' + ]); + + $sessionKey = 'user_' . $user->id . '_current_role'; + + $user->current_role_id = $data['role_id']; + $user->save(); + + return redirect()->route('start')->setStatusCode(302); + } } diff --git a/app/Http/Middleware/HandleInertiaRequests.php b/app/Http/Middleware/HandleInertiaRequests.php index 56f8aff..855c8da 100644 --- a/app/Http/Middleware/HandleInertiaRequests.php +++ b/app/Http/Middleware/HandleInertiaRequests.php @@ -45,6 +45,7 @@ class HandleInertiaRequests extends Middleware 'token' => Session::get('token'), 'permissions' => $user->permissions(), 'role' => $user->currentRole(), + 'available_roles' => $user->roles, 'available_departments' => $user->availableDepartments(), 'current_department' => $user->department ] : null, diff --git a/app/Http/Resources/Mis/FormattedPatientResource.php b/app/Http/Resources/Mis/FormattedPatientResource.php index a2ac102..fe5bc02 100644 --- a/app/Http/Resources/Mis/FormattedPatientResource.php +++ b/app/Http/Resources/Mis/FormattedPatientResource.php @@ -2,6 +2,7 @@ namespace App\Http\Resources\Mis; +use App\Models\MisSurgicalOperation; use Illuminate\Http\Request; use Illuminate\Http\Resources\Json\JsonResource; use Illuminate\Support\Carbon; @@ -25,6 +26,15 @@ class FormattedPatientResource extends JsonResource 'name' => $this->migrations()->first()->diagnosis()->first()?->mkb()->first()->NAME ?? null, ]; }), + 'operations' => $this->whenLoaded('surgicalOperations', function () { + return $this->surgicalOperations()->where('rf_StationarBranchID', $this->misStationarBranchId) + ->get() + ->map(function (MisSurgicalOperation $operation) { + return [ + 'code' => $operation->serviceMedical->ServiceMedicalCode ?? null, + ]; + }); + }), 'fullname' => Str::ucwords(Str::lower("$this->FAMILY $this->Name $this->OT")), 'age' => Carbon::parse($this->BD)->diff(Carbon::now())->format('%y'), 'birth_date' => Carbon::parse($this->BD)->format('d.m.Y'), diff --git a/app/Models/MisMedicalHistory.php b/app/Models/MisMedicalHistory.php index 8cdf51d..a9ebd39 100644 --- a/app/Models/MisMedicalHistory.php +++ b/app/Models/MisMedicalHistory.php @@ -24,6 +24,22 @@ class MisMedicalHistory extends Model 'DateRecipient' => 'datetime' ]; + public function observationPatient() + { + return $this->belongsTo(ObservationPatient::class, 'MedicalHistoryID', 'rf_medicalhistory_id'); + } + + public function surgicalOperations() + { + return $this->hasMany(MisSurgicalOperation::class, 'rf_MedicalHistoryID', 'MedicalHistoryID'); + } + + public function scopeCurrentlyHospitalized($query) + { + return $query->whereDate('DateExtract', '1900-01-01') + ->where('MedicalHistoryID', '<>', 0); + } + /* * Истории со срочностью - Плановая */ diff --git a/app/Models/MisMigrationPatient.php b/app/Models/MisMigrationPatient.php index fc96b93..77f3406 100644 --- a/app/Models/MisMigrationPatient.php +++ b/app/Models/MisMigrationPatient.php @@ -3,6 +3,7 @@ namespace App\Models; use Illuminate\Database\Eloquent\Model; +use Illuminate\Support\Carbon; class MisMigrationPatient extends Model { @@ -23,4 +24,45 @@ class MisMigrationPatient extends Model { return $this->hasOne(MisMKB::class, 'MKBID', 'rf_MKBID'); } + + public function scopeCurrentlyInTreatment($query, $branchId = null) + { + $query->where('rf_kl_VisitResultID', 0) + ->where('rf_MedicalHistoryID', '<>', 0); + + if ($branchId) { + $query->where('rf_StationarBranchID', $branchId); + } + + return $query; + } + + public function scopeWhereInDepartment($query, $branchId = null) + { + $query->where('rf_MedicalHistoryID', '<>', 0); + + if ($branchId) { + $query->where('rf_StationarBranchID', $branchId); + } + + return $query; + } + + public function scopeExtractedToday($query, $branchId = null, $startDate = null, $endDate = null) + { + if (is_null($startDate)) $startDate = Carbon::now()->addDays(-1)->format('Y-m-d'); + if (is_null($endDate)) $endDate = Carbon::now()->format('Y-m-d'); + + $query->where('rf_kl_VisitResultID', '<>', 0) + ->where('rf_MedicalHistoryID', '<>', 0) + ->when($startDate && $endDate, function($query) use ($startDate, $endDate) { + return $query->whereBetween('DateOut', [$startDate, $endDate]); + }); + + if ($branchId) { + $query->where('rf_StationarBranchID', $branchId); + } + + return $query; + } } diff --git a/app/Models/MisServiceMedical.php b/app/Models/MisServiceMedical.php new file mode 100644 index 0000000..e8b30dd --- /dev/null +++ b/app/Models/MisServiceMedical.php @@ -0,0 +1,16 @@ +hsaMany(MisServiceMedical::class, 'ServiceMedicalID', 'rf_ServiceMedicalID'); + } +} diff --git a/app/Models/MisSurgicalOperation.php b/app/Models/MisSurgicalOperation.php new file mode 100644 index 0000000..1cb3e43 --- /dev/null +++ b/app/Models/MisSurgicalOperation.php @@ -0,0 +1,16 @@ +belongsTo(MisServiceMedical::class, 'rf_kl_ServiceMedicalID', 'ServiceMedicalID'); + } +} diff --git a/app/Models/ObservationPatient.php b/app/Models/ObservationPatient.php index 8fdd51e..3e358ae 100644 --- a/app/Models/ObservationPatient.php +++ b/app/Models/ObservationPatient.php @@ -14,6 +14,7 @@ class ObservationPatient extends Model 'rf_mkab_id', 'rf_department_id', 'rf_report_id', + 'comment' ]; public function history() diff --git a/app/Models/UnwantedEvent.php b/app/Models/UnwantedEvent.php new file mode 100644 index 0000000..4b8708e --- /dev/null +++ b/app/Models/UnwantedEvent.php @@ -0,0 +1,15 @@ +roles()->where('is_default', true)->first()->role_id; - $roleId = session('currentRoleId', $defaultRoleId); + $sessionKey = 'user_' . $this->id . '_current_role'; + $roleId = $this->current_role_id ?? $defaultRoleId; $role = Role::where('role_id', $roleId)->first(); @@ -101,11 +103,6 @@ class User extends Authenticatable return $this->currentRole()->slug === 'head_of_department'; } - public function isStatistician() - { - return $this->currentRole()->slug === 'statistician'; - } - // Получение доступных отделений public function availableDepartments() { @@ -134,11 +131,6 @@ class User extends Authenticatable $permissions['manage_users'] = $this->isAdmin(); } - if ($this->isStatistician()) { - $permissions['view_statistics'] = true; - $permissions['export_data'] = true; - } - return $permissions; } } diff --git a/database/migrations/2026_01_21_170206_add_comment_column_in_observation_patients_table.php b/database/migrations/2026_01_21_170206_add_comment_column_in_observation_patients_table.php new file mode 100644 index 0000000..17e1adc --- /dev/null +++ b/database/migrations/2026_01_21_170206_add_comment_column_in_observation_patients_table.php @@ -0,0 +1,28 @@ +text('comment')->nullable(); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::table('observation_patients', function (Blueprint $table) { + $table->dropColumn('comment'); + }); + } +}; diff --git a/database/migrations/2026_01_22_142054_add_column_current_role_id_in_users_table.php b/database/migrations/2026_01_22_142054_add_column_current_role_id_in_users_table.php new file mode 100644 index 0000000..c5dcfe6 --- /dev/null +++ b/database/migrations/2026_01_22_142054_add_column_current_role_id_in_users_table.php @@ -0,0 +1,28 @@ +unsignedBigInteger('current_role_id')->nullable(); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::table('users', function (Blueprint $table) { + $table->dropColumn('current_role_id'); + }); + } +}; diff --git a/database/migrations/2026_01_22_152242_create_unwanted_events_table.php b/database/migrations/2026_01_22_152242_create_unwanted_events_table.php new file mode 100644 index 0000000..65ff960 --- /dev/null +++ b/database/migrations/2026_01_22_152242_create_unwanted_events_table.php @@ -0,0 +1,29 @@ +id('unwanted_event_id'); + $table->foreignIdFor(\App\Models\Report::class, 'rf_report_id'); + $table->text('comment'); + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::dropIfExists('unwanted_events'); + } +}; diff --git a/resources/js/Components/DepartmentSelect.vue b/resources/js/Components/DepartmentSelect.vue new file mode 100644 index 0000000..2e093c3 --- /dev/null +++ b/resources/js/Components/DepartmentSelect.vue @@ -0,0 +1,22 @@ + + + + + diff --git a/resources/js/Components/ReportSelectDate.vue b/resources/js/Components/ReportSelectDate.vue index b6290f2..8ec4511 100644 --- a/resources/js/Components/ReportSelectDate.vue +++ b/resources/js/Components/ReportSelectDate.vue @@ -23,10 +23,10 @@ const { timestampCurrentRange } = storeToRefs(reportStore) diff --git a/resources/js/Layouts/Components/AppHeader.vue b/resources/js/Layouts/Components/AppHeader.vue index 84e8660..f2f850e 100644 --- a/resources/js/Layouts/Components/AppHeader.vue +++ b/resources/js/Layouts/Components/AppHeader.vue @@ -7,18 +7,13 @@ import AppHeaderRole from "./AppHeaderRole.vue"; diff --git a/resources/js/Pages/Report/Index.vue b/resources/js/Pages/Report/Index.vue index 378926c..c756b0a 100644 --- a/resources/js/Pages/Report/Index.vue +++ b/resources/js/Pages/Report/Index.vue @@ -2,17 +2,26 @@ import AppLayout from "../../Layouts/AppLayout.vue"; import ReportForm from "./Components/ReportForm.vue"; import {useReportStore} from "../../Stores/report.js"; -import {onMounted} from "vue"; +import {computed, onMounted} from "vue"; +import {useAuthStore} from "../../Stores/auth.js"; const reportStore = useReportStore() +const authStore = useAuthStore() onMounted(async () => { await reportStore.getReportInfo() }) + +const mode = computed(() => { + if (authStore.isHeadOfDepartment) + return 'readonly' + return 'fillable' +}) + diff --git a/resources/js/Stores/auth.js b/resources/js/Stores/auth.js index 0099a1f..fd66701 100644 --- a/resources/js/Stores/auth.js +++ b/resources/js/Stores/auth.js @@ -1,13 +1,23 @@ -import { ref, computed } from 'vue' +import {ref, computed, watch} from 'vue' import { defineStore } from 'pinia' import axios from 'axios' import {usePage} from "@inertiajs/vue3"; export const useAuthStore = defineStore('authStore', () => { - const user = usePage().props.user - const token = user?.token - const permissions = user?.permissions - const availableDepartments = ref(user?.available_departments) + const page = usePage() + const user = ref(page.props.user) + const token = computed(() => user.value?.token) + const role = computed(() => user.value?.role) + const permissions = computed(() => user.value?.permissions) + const availableDepartments = computed(() => user.value?.available_departments) + const availableRoles = computed(() => user.value?.available_roles) + + watch( + () => page.props.user, + (newUser) => { + user.value = newUser + }, + { deep: true, immediate: true }) // Инициализация axios с токеном if (token?.value) { @@ -16,12 +26,10 @@ export const useAuthStore = defineStore('authStore', () => { // Вычисляемые свойства const isAuthenticated = computed(() => !!user.value && !!token.value) - const isAdmin = computed(() => user.role === 'admin') - const isDoctor = computed(() => user.role === 'doctor') - const isNurse = computed(() => user.role === 'nurse') - const isHeadOfDepartment = computed(() => user.role === 'head_of_department') - const isStatistician = computed(() => user.role === 'statistician') - const userDepartment = computed(() => user.current_department || '') + const isAdmin = computed(() => role.value?.slug === 'admin') + const isDoctor = computed(() => role.value?.slug === 'doctor') + const isHeadOfDepartment = computed(() => role.value?.slug === 'head_of_department') + const userDepartment = computed(() => user.value?.current_department || '') const clearAuthData = () => { user.value = null @@ -59,12 +67,11 @@ export const useAuthStore = defineStore('authStore', () => { token, permissions, availableDepartments, + availableRoles, isAuthenticated, isAdmin, isDoctor, - isNurse, isHeadOfDepartment, - isStatistician, userDepartment, clearAuthData, diff --git a/resources/js/Stores/report.js b/resources/js/Stores/report.js index 9d6aa3c..a29adeb 100644 --- a/resources/js/Stores/report.js +++ b/resources/js/Stores/report.js @@ -19,7 +19,7 @@ export const useReportStore = defineStore('reportStore', () => { } }) - const timestampCurrentRange = ref([timestampNow.value, timestampNow.value]) + const timestampCurrentRange = ref([null, null]) const dataOnReport = ref(null) @@ -74,6 +74,9 @@ export const useReportStore = defineStore('reportStore', () => { const form = { metrics: reportForm.value, observationPatients: patientsData.value['observation'], + unwantedEvent: { + comment: reportForm.comment + }, ...assignForm } @@ -99,21 +102,40 @@ export const useReportStore = defineStore('reportStore', () => { await axios.get('/api/report') .then((res) => { reportInfo.value = res.data + + reportForm.value.metrika_item_3 = reportInfo.value.department?.recipientCount + reportForm.value.metrika_item_7 = reportInfo.value.department?.extractCount + reportForm.value.metrika_item_8 = reportInfo.value.department?.currentCount + + timestampCurrentRange.value = [ + reportInfo.value.dates.startAt, + reportInfo.value.dates.endAt, + ] }) .finally(() => { isLoadReportInfo.value = false }) } - const getDataOnReportDate = async () => { - await axios.get(`/api/metric-forms/1/report-by-date?sent_at=${timestampCurrentRange.value}`) - .then(res => { - dataOnReport.value = res.data - }) - .catch(err => { - // Отчета на выбранную дату не найдено - if (err.code === 404) {} - }) + const getDataOnReportDate = async (dateRange) => { + isLoadReportInfo.value = true + timestampCurrentRange.value = dateRange + await axios.get(`/api/report?startAt=${timestampCurrentRange.value[0]}&endAt=${timestampCurrentRange.value[1]}`) + .then((res) => { + reportInfo.value = res.data + + reportForm.value.metrika_item_3 = reportInfo.value.department?.recipientCount + reportForm.value.metrika_item_7 = reportInfo.value.department?.extractCount + reportForm.value.metrika_item_8 = reportInfo.value.department?.currentCount + + timestampCurrentRange.value = [ + reportInfo.value.dates.startAt, + reportInfo.value.dates.endAt, + ] + }) + .finally(() => { + isLoadReportInfo.value = false + }) } return { diff --git a/routes/web.php b/routes/web.php index 07df975..28418d1 100644 --- a/routes/web.php +++ b/routes/web.php @@ -27,6 +27,11 @@ Route::get('/report', [\App\Http\Controllers\Web\ReportController::class, 'index Route::get('/statistic', [\App\Http\Controllers\Web\StatisticController::class, 'index']) ->middleware(['auth']) ->name('statistic'); + +Route::post('/user/role/change', [\App\Http\Controllers\AuthController::class, 'changeRole']) + ->middleware(['auth']) + ->name('user.role.change'); + Route::get('/path/patient', function () { return \Inertia\Inertia::render('Path/Patient'); })