Добавлено сохранение правок поверх МИС

Добавлено версионирование сохраненных правок
Добавлено сохранение отчета мед. сестры
This commit is contained in:
brusnitsyn
2026-05-04 22:23:21 +09:00
parent 7a58812072
commit 82673f385b
9 changed files with 241 additions and 23 deletions

View File

@@ -4,14 +4,16 @@ namespace App\Http\Controllers\Api;
use App\Http\Controllers\Controller;
use App\Models\MedicalHistory;
use App\Models\MedicalHistoryCorrection;
use App\Models\MedicalHistoryNurse;
use App\Models\UnifiedMedicalHistory;
use Illuminate\Http\Request;
class NurseController extends Controller
{
public function getPatient($id, Request $request)
{
return MedicalHistory::where('id', $id)->first();
return UnifiedMedicalHistory::where('id', $id)->first();
}
public function searchPatients(Request $request)
@@ -54,4 +56,31 @@ class NurseController extends Controller
'data' => $result,
], 201);
}
public function storeCorrection($id, Request $request)
{
$data = $request->validate([
'medical_card_number' => 'nullable',
'full_name' => 'nullable',
'birth_date' => 'nullable',
'recipient_date' => 'nullable',
'extract_date' => 'nullable',
'death_date' => 'nullable',
'male' => 'nullable',
'urgency_id' => 'nullable',
'hospital_result_id' => 'nullable',
'visit_result_id' => 'nullable',
'mis_user_id' => 'nullable',
'comment' => 'nullable',
]);
$data['medical_history_id'] = $id;
$data['user_id'] = auth()->user()->id;
$result = MedicalHistoryCorrection::create($data);
return response()->json([
'data' => $result,
], 201);
}
}

View File

@@ -5,7 +5,7 @@ namespace App\Http\Controllers\Web;
use App\Http\Controllers\Controller;
use App\Models\Department;
use App\Services\DateRangeService;
use App\Services\MedicalHistoryService;
use App\Services\UnifiedMedicalHistoryService;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Inertia\Inertia;
@@ -14,7 +14,7 @@ class NurseReportController extends Controller
{
public function __construct(
protected DateRangeService $dateRangeService,
protected MedicalHistoryService $medicalHistoryService
protected UnifiedMedicalHistoryService $unifiedMedicalHistoryService
)
{}
@@ -30,11 +30,11 @@ class NurseReportController extends Controller
$department = Department::where('department_id', $departmentId)->firstOrFail();
$dateRange = $this->dateRangeService->getDateRangeFromRequest($request, $user);
$inDepartmentHistories = $this->medicalHistoryService->getDepartmentHistories($dateRange, $department->rf_mis_department_id);
$recipientHistories = $this->medicalHistoryService->getRecipientHistories($dateRange, $department->rf_mis_department_id);
$dischargedHistories = $this->medicalHistoryService->getDischargedHistories($dateRange, $department->rf_mis_department_id);
$deceasedHistories = $this->medicalHistoryService->getDeceasedHistories($dateRange, $department->rf_mis_department_id);
$transferredHistories = $this->medicalHistoryService->getTransferredHistories($dateRange, $department->rf_mis_department_id);
$inDepartmentHistories = $this->unifiedMedicalHistoryService->getDepartmentHistories($dateRange, $department->rf_mis_department_id);
$recipientHistories = $this->unifiedMedicalHistoryService->getRecipientHistories($dateRange, $department->rf_mis_department_id);
$dischargedHistories = $this->unifiedMedicalHistoryService->getDischargedHistories($dateRange, $department->rf_mis_department_id);
$deceasedHistories = $this->unifiedMedicalHistoryService->getDeceasedHistories($dateRange, $department->rf_mis_department_id);
$transferredHistories = $this->unifiedMedicalHistoryService->getTransferredHistories($dateRange, $department->rf_mis_department_id);
return Inertia::render('Nurse/Report/Index', [
'inDepartmentHistories' => $inDepartmentHistories,

View File

@@ -18,6 +18,9 @@ class MedicalHistoryCorrection extends Model
'urgency_id',
'hospital_result_id',
'visit_result_id',
'user_id',
'mis_user_id',
'comment',
];
protected $casts = [

View File

@@ -6,7 +6,7 @@ use Illuminate\Database\Eloquent\Model;
class UnifiedMedicalHistory extends MaterializedViewModel
{
protected $table = 'v_unified_medical_history';
protected $table = 'v_unified_medical_history_nurse';
protected $primaryKey = 'id';
protected $casts = [
@@ -16,4 +16,31 @@ class UnifiedMedicalHistory extends MaterializedViewModel
'death_date' => 'datetime',
'male' => 'boolean',
];
public function migrations(): \Illuminate\Database\Eloquent\Relations\HasMany|MedicalHistory
{
return $this->hasMany(MigrationPatient::class, 'medical_history_id', 'id');
}
public function operations(): \Illuminate\Database\Eloquent\Relations\HasMany|MedicalHistory
{
return $this->hasMany(SurgicalOperation::class, 'medical_history_id', 'id');
}
public function latestMigration()
{
return $this->hasOne(MigrationPatient::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,118 @@
<?php
namespace App\Services;
use App\Models\MedicalHistory;
use App\Models\MigrationPatient;
use App\Models\UnifiedMedicalHistory;
use Illuminate\Support\Carbon;
class UnifiedMedicalHistoryService
{
public function getHistories(DateRange $dateRange, int $departmentId)
{
$query = UnifiedMedicalHistory::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 = UnifiedMedicalHistory::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 UnifiedMedicalHistory::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 UnifiedMedicalHistory::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 UnifiedMedicalHistory::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 UnifiedMedicalHistory::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 UnifiedMedicalHistory::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,28 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::table('medical_history_corrections', function (Blueprint $table) {
$table->integer('mis_user_id')->nullable()->change();
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::table('medical_history_corrections', function (Blueprint $table) {
$table->integer('mis_user_id')->change();
});
}
};

View File

@@ -64,13 +64,18 @@ const visitResultOptions = [
]
const submit = () => {
axios.post(`/api/nurse/patients/${form.value.patient_id}/correction`, {
...form.value
}).then(res => {
console.log(res)
})
}
const fetchPatient = async (historyId) => {
loading.value = true
await axios.get(`/api/nurse/patients/${historyId}`)
.then(res => {
form.value.patient_id = historyId
form.value.full_name = res.data.full_name
form.value.urgency_id = res.data.urgency_id
form.value.visit_result_id = res.data.visit_result_id

View File

@@ -5,8 +5,8 @@ import AppContainer from "../../../Components/AppContainer.vue";
import AppPanel from "../../../Components/AppPanel.vue";
import DatePickerQuery from "../../../Components/DatePickerQuery.vue";
import UrgencyBadge from "../../../Components/UrgencyBadge.vue";
import {computed, h, ref, shallowRef} from "vue"
import {TbArrowMoveRight, TbArrowMoveUp, TbEdit, TbCirclePlus, TbPencil} from 'vue-icons-plus/tb'
import {h, ref, shallowRef} from "vue"
import {TbCirclePlus, TbPencil} from 'vue-icons-plus/tb'
import {useAuthStore} from "../../../Stores/auth.js";
import AddMedicalHistoryModal from "../Components/AddMedicalHistoryModal.vue";
import EditMedicalHistoryModal from "../Components/EditMedicalHistoryModal.vue";
@@ -84,6 +84,10 @@ const onClickEditButton = (historyId) => {
editHistoryId.value = historyId
}
const submit = () => {
// TODO: сохранение отчета и пациентов
}
const formattedLabel = (word, count) => {
return `${word} (${count})`
}
@@ -97,7 +101,7 @@ const formattedLabel = (word, count) => {
<NTag type="info" :bordered="false">
{{ userDepartment.name_full }}
</NTag>
<DatePickerQuery :date="dates" />
<DatePickerQuery :date="dates" class="text-lg!" />
</NFlex>
</AppPanel>
<AppPanel header="Пациенты в отделении" header-include-body>
@@ -116,44 +120,47 @@ const formattedLabel = (word, count) => {
<NDataTable :columns="columns"
:data="inDepartmentHistories"
table-layout="fixed"
max-height="calc(100vh - 375px)"
min-height="calc(100vh - 375px)"
max-height="calc(100vh - 435px)"
min-height="calc(100vh - 435px)"
/>
</NTabPane>
<NTabPane name="income" :tab="formattedLabel('Поступившие', recipientHistories.length)">
<NDataTable :columns="columns"
:data="recipientHistories"
table-layout="fixed"
max-height="calc(100vh - 375px)"
min-height="calc(100vh - 375px)"
max-height="calc(100vh - 435px)"
min-height="calc(100vh - 435px)"
/>
</NTabPane>
<NTabPane name="outcome" :tab="formattedLabel('Выписанные', dischargedHistories.length)">
<NDataTable :columns="columns"
:data="dischargedHistories"
table-layout="fixed"
max-height="calc(100vh - 375px)"
min-height="calc(100vh - 375px)"
max-height="calc(100vh - 435px)"
min-height="calc(100vh - 435px)"
/>
</NTabPane>
<NTabPane name="dead" :tab="formattedLabel('Умершие', deceasedHistories.length)">
<NDataTable :columns="columns"
:data="deceasedHistories"
table-layout="fixed"
max-height="calc(100vh - 375px)"
min-height="calc(100vh - 375px)"
max-height="calc(100vh - 435px)"
min-height="calc(100vh - 435px)"
/>
</NTabPane>
<NTabPane name="transfer" :tab="formattedLabel('Переведенные', transferredHistories.length)">
<NDataTable :columns="columns"
:data="transferredHistories"
table-layout="fixed"
max-height="calc(100vh - 375px)"
min-height="calc(100vh - 375px)"
max-height="calc(100vh - 435px)"
min-height="calc(100vh - 435px)"
/>
</NTabPane>
</NTabs>
</AppPanel>
<NButton secondary size="large">
Сохранить отчет
</NButton>
</AppContainer>
<AddMedicalHistoryModal v-model:show="showAddMedicalHistoryModal" />
<EditMedicalHistoryModal v-model:show="showEditMedicalHistoryModal" :history-id="editHistoryId" />

View File

@@ -96,6 +96,7 @@ Route::middleware(['auth:sanctum'])->group(function () {
Route::prefix('patients')->group(function () {
Route::prefix('{id}')->group(function () {
Route::get('/', [\App\Http\Controllers\Api\NurseController::class, 'getPatient']);
Route::post('/correction', [\App\Http\Controllers\Api\NurseController::class, 'storeCorrection']);
});
Route::post('/search', [\App\Http\Controllers\Api\NurseController::class, 'searchPatients']);
Route::post('/', [\App\Http\Controllers\Api\NurseController::class, 'storePatient']);