Обновлен стартовый экран
Переписаны запросы для статистики, отчетов Добавлена интеграция отчета сестры
This commit is contained in:
@@ -9,10 +9,8 @@ class AdminController extends Controller
|
||||
{
|
||||
public function index()
|
||||
{
|
||||
return Inertia::render('Admin/Index',
|
||||
[
|
||||
abort_unless(auth()->user()->isAdmin(), 403);
|
||||
|
||||
]
|
||||
);
|
||||
return Inertia::render('Admin/Index', []);
|
||||
}
|
||||
}
|
||||
|
||||
199
app/Http/Controllers/Web/Admin/MetrikaController.php
Normal file
199
app/Http/Controllers/Web/Admin/MetrikaController.php
Normal file
@@ -0,0 +1,199 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Web\Admin;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\MetrikaGroup;
|
||||
use App\Models\MetrikaGroupItem;
|
||||
use App\Models\MetrikaItem;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Str;
|
||||
use Inertia\Inertia;
|
||||
|
||||
class MetrikaController extends Controller
|
||||
{
|
||||
public function index()
|
||||
{
|
||||
abort_unless(auth()->user()->isAdmin(), 403);
|
||||
|
||||
$groups = MetrikaGroup::withCount('groupItems')->get()->map(fn($g) => [
|
||||
'id' => $g->metrika_group_id,
|
||||
'name' => $g->name,
|
||||
'description' => $g->description,
|
||||
'items_count' => $g->group_items_count,
|
||||
]);
|
||||
|
||||
$items = MetrikaItem::all()->map(fn($i) => [
|
||||
'id' => $i->metrika_item_id,
|
||||
'name' => $i->name,
|
||||
'description' => $i->description,
|
||||
'data_type' => $i->data_type,
|
||||
'is_active' => $i->is_active,
|
||||
'code' => $i->code,
|
||||
]);
|
||||
|
||||
return Inertia::render('Admin/Metrics/Index', [
|
||||
'groups' => $groups,
|
||||
'items' => $items,
|
||||
]);
|
||||
}
|
||||
|
||||
// ── Группы ──
|
||||
|
||||
public function createGroup()
|
||||
{
|
||||
abort_unless(auth()->user()->isAdmin(), 403);
|
||||
|
||||
return Inertia::render('Admin/Metrics/Group', [
|
||||
'group' => null,
|
||||
'itemIds' => [],
|
||||
'allItems' => $this->allItems(),
|
||||
]);
|
||||
}
|
||||
|
||||
public function storeGroup(Request $request)
|
||||
{
|
||||
abort_unless(auth()->user()->isAdmin(), 403);
|
||||
|
||||
$validated = $request->validate([
|
||||
'name' => 'required|string|max:255',
|
||||
'description' => 'nullable|string',
|
||||
'items' => 'array',
|
||||
'items.*' => 'integer|exists:metrika_items,metrika_item_id',
|
||||
]);
|
||||
|
||||
$group = MetrikaGroup::create([
|
||||
'name' => $validated['name'],
|
||||
'description' => $validated['description'] ?? null,
|
||||
]);
|
||||
|
||||
foreach ($validated['items'] ?? [] as $itemId) {
|
||||
MetrikaGroupItem::create([
|
||||
'rf_metrika_group_id' => $group->metrika_group_id,
|
||||
'rf_metrika_item_id' => $itemId,
|
||||
]);
|
||||
}
|
||||
|
||||
return redirect('/admin/metrics')->with('success', 'Группа создана');
|
||||
}
|
||||
|
||||
public function showGroup(MetrikaGroup $group)
|
||||
{
|
||||
abort_unless(auth()->user()->isAdmin(), 403);
|
||||
|
||||
$itemIds = MetrikaGroupItem::where('rf_metrika_group_id', $group->metrika_group_id)
|
||||
->pluck('rf_metrika_item_id')
|
||||
->toArray();
|
||||
|
||||
return Inertia::render('Admin/Metrics/Group', [
|
||||
'group' => ['id' => $group->metrika_group_id, 'name' => $group->name, 'description' => $group->description],
|
||||
'itemIds' => $itemIds,
|
||||
'allItems' => $this->allItems(),
|
||||
]);
|
||||
}
|
||||
|
||||
public function updateGroup(MetrikaGroup $group, Request $request)
|
||||
{
|
||||
abort_unless(auth()->user()->isAdmin(), 403);
|
||||
|
||||
$validated = $request->validate([
|
||||
'name' => 'required|string|max:255',
|
||||
'description' => 'nullable|string',
|
||||
'items' => 'array',
|
||||
'items.*' => 'integer|exists:metrika_items,metrika_item_id',
|
||||
]);
|
||||
|
||||
$group->update([
|
||||
'name' => $validated['name'],
|
||||
'description' => $validated['description'] ?? null,
|
||||
]);
|
||||
|
||||
MetrikaGroupItem::where('rf_metrika_group_id', $group->metrika_group_id)->delete();
|
||||
foreach ($validated['items'] ?? [] as $itemId) {
|
||||
MetrikaGroupItem::create([
|
||||
'rf_metrika_group_id' => $group->metrika_group_id,
|
||||
'rf_metrika_item_id' => $itemId,
|
||||
]);
|
||||
}
|
||||
|
||||
return redirect('/admin/metrics')->with('success', 'Группа сохранена');
|
||||
}
|
||||
|
||||
// ── Показатели ──
|
||||
|
||||
public function createItem()
|
||||
{
|
||||
abort_unless(auth()->user()->isAdmin(), 403);
|
||||
|
||||
return Inertia::render('Admin/Metrics/Item', ['item' => null]);
|
||||
}
|
||||
|
||||
public function storeItem(Request $request)
|
||||
{
|
||||
abort_unless(auth()->user()->isAdmin(), 403);
|
||||
|
||||
$validated = $request->validate([
|
||||
'name' => 'required|string|max:255',
|
||||
'description' => 'nullable|string',
|
||||
'data_type' => 'required|string|in:integer,float,string,text,boolean,select',
|
||||
'is_active' => 'required|boolean',
|
||||
'is_required' => 'boolean',
|
||||
'default_value' => 'nullable|string',
|
||||
'placeholder' => 'nullable|string',
|
||||
]);
|
||||
|
||||
MetrikaItem::create([
|
||||
...$validated,
|
||||
'code' => Str::slug($validated['name']),
|
||||
]);
|
||||
|
||||
return redirect('/admin/metrics')->with('success', 'Показатель создан');
|
||||
}
|
||||
|
||||
public function showItem(MetrikaItem $item)
|
||||
{
|
||||
abort_unless(auth()->user()->isAdmin(), 403);
|
||||
|
||||
return Inertia::render('Admin/Metrics/Item', [
|
||||
'item' => [
|
||||
'id' => $item->metrika_item_id,
|
||||
'name' => $item->name,
|
||||
'description' => $item->description,
|
||||
'data_type' => $item->data_type,
|
||||
'is_active' => $item->is_active,
|
||||
'is_required' => $item->is_required,
|
||||
'default_value' => $item->default_value,
|
||||
'placeholder' => $item->placeholder,
|
||||
'code' => $item->code,
|
||||
],
|
||||
]);
|
||||
}
|
||||
|
||||
public function updateItem(MetrikaItem $item, Request $request)
|
||||
{
|
||||
abort_unless(auth()->user()->isAdmin(), 403);
|
||||
|
||||
$validated = $request->validate([
|
||||
'name' => 'required|string|max:255',
|
||||
'description' => 'nullable|string',
|
||||
'data_type' => 'required|string|in:integer,float,string,text,boolean,select',
|
||||
'is_active' => 'required|boolean',
|
||||
'is_required' => 'boolean',
|
||||
'default_value' => 'nullable|string',
|
||||
'placeholder' => 'nullable|string',
|
||||
]);
|
||||
|
||||
$item->update($validated);
|
||||
|
||||
return redirect('/admin/metrics')->with('success', 'Показатель сохранён');
|
||||
}
|
||||
|
||||
private function allItems(): array
|
||||
{
|
||||
return MetrikaItem::where('is_active', true)->get()->map(fn($i) => [
|
||||
'metrika_item_id' => $i->metrika_item_id,
|
||||
'name' => $i->name,
|
||||
'data_type' => $i->data_type,
|
||||
])->toArray();
|
||||
}
|
||||
}
|
||||
@@ -7,14 +7,17 @@ use App\Models\Department;
|
||||
use App\Models\Role;
|
||||
use App\Models\User;
|
||||
use App\Models\UserDepartment;
|
||||
use App\Models\UserRole;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Hash;
|
||||
use Inertia\Inertia;
|
||||
|
||||
class UserController extends Controller
|
||||
{
|
||||
public function index()
|
||||
{
|
||||
$users = User::with(['roles', 'department'])->get()->map(function ($user) {
|
||||
abort_unless(auth()->user()->isAdmin(), 403);
|
||||
$users = User::with(['appRoles', 'department'])->get()->map(function ($user) {
|
||||
return [
|
||||
'id' => $user->id,
|
||||
'name' => $user->name,
|
||||
@@ -25,76 +28,169 @@ class UserController extends Controller
|
||||
];
|
||||
});
|
||||
|
||||
return Inertia::render('Admin/Users/Index',
|
||||
[
|
||||
'users' => $users,
|
||||
]
|
||||
);
|
||||
return Inertia::render('Admin/Users/Index', ['users' => $users]);
|
||||
}
|
||||
|
||||
public function create()
|
||||
{
|
||||
$rolesData = Role::all()->map(function ($role) {
|
||||
return [
|
||||
'role_id' => $role->role_id,
|
||||
'name' => $role->name,
|
||||
];
|
||||
});
|
||||
|
||||
$departmentData = Department::all()->map(function (Department $department) {
|
||||
return [
|
||||
'department_id' => $department->department_id,
|
||||
'name_full' => $department->name_full,
|
||||
];
|
||||
});
|
||||
abort_unless(auth()->user()->isAdmin(), 403);
|
||||
|
||||
return Inertia::render('Admin/Users/Create', [
|
||||
'departments' => $departmentData,
|
||||
'roles' => $rolesData,
|
||||
'departments' => $this->allDepartments(),
|
||||
'roles' => $this->allRoles(),
|
||||
]);
|
||||
}
|
||||
|
||||
public function store(Request $request)
|
||||
{
|
||||
abort_unless(auth()->user()->isAdmin(), 403);
|
||||
|
||||
$validated = $request->validate([
|
||||
'name' => 'required|string',
|
||||
'login' => 'required|string',
|
||||
'password' => 'required|string',
|
||||
'is_active' => 'required|boolean',
|
||||
'name' => 'required|string|max:255',
|
||||
'login' => 'required|string|max:255|unique:users,login',
|
||||
'password' => 'required|string|min:6',
|
||||
'is_active' => 'required|boolean',
|
||||
'department_id' => 'required|integer|exists:departments,department_id',
|
||||
'departments' => 'array',
|
||||
'departments.*' => 'integer|exists:departments,department_id',
|
||||
'roles' => 'required|array|min:1',
|
||||
'roles.*' => 'integer|exists:roles,role_id',
|
||||
]);
|
||||
|
||||
dd($validated);
|
||||
$user = User::create([
|
||||
'name' => $validated['name'],
|
||||
'login' => $validated['login'],
|
||||
'password' => Hash::make($validated['password']),
|
||||
'is_active' => $validated['is_active'],
|
||||
'rf_department_id' => $validated['department_id'],
|
||||
]);
|
||||
|
||||
// Назначаем роли — первая роль становится дефолтной
|
||||
foreach ($validated['roles'] as $i => $roleId) {
|
||||
UserRole::create([
|
||||
'rf_user_id' => $user->id,
|
||||
'rf_role_id' => $roleId,
|
||||
'is_active' => true,
|
||||
'is_default' => $i === 0,
|
||||
]);
|
||||
}
|
||||
|
||||
// Привязываем дополнительные отделения
|
||||
foreach ($validated['departments'] ?? [] as $i => $deptId) {
|
||||
UserDepartment::create([
|
||||
'rf_user_id' => $user->id,
|
||||
'rf_department_id' => $deptId,
|
||||
'is_favorite' => false,
|
||||
'order' => $i,
|
||||
]);
|
||||
}
|
||||
|
||||
return redirect('/admin/users')->with('success', 'Пользователь создан');
|
||||
}
|
||||
|
||||
public function show(User $user, Request $request)
|
||||
public function show(User $user)
|
||||
{
|
||||
abort_unless(auth()->user()->isAdmin(), 403);
|
||||
|
||||
$userData = [
|
||||
'id' => $user->id,
|
||||
'name' => $user->name,
|
||||
'login' => $user->login,
|
||||
'is_active' => $user->is_active,
|
||||
'created_at' => $user->created_at->format('d.m.Y H:i:s'),
|
||||
'updated_at' => $user->updated_at->format('d.m.Y H:i:s'),
|
||||
'id' => $user->id,
|
||||
'name' => $user->name,
|
||||
'login' => $user->login,
|
||||
'is_active' => $user->is_active,
|
||||
'department_id' => $user->rf_department_id,
|
||||
'created_at' => $user->created_at->format('d.m.Y H:i:s'),
|
||||
'updated_at' => $user->updated_at->format('d.m.Y H:i:s'),
|
||||
];
|
||||
|
||||
$rolesData = $user->roles->map(function ($role) {
|
||||
return [
|
||||
'role_id' => $role->role_id,
|
||||
'name' => $role->name,
|
||||
];
|
||||
});
|
||||
$userRoleIds = $user->userRoles()->pluck('rf_role_id')->toArray();
|
||||
|
||||
$departmentData = $user->departments->map(function (UserDepartment $userDepartment) {
|
||||
return [
|
||||
'department_id' => $userDepartment->department->department_id,
|
||||
'name_full' => $userDepartment->department->name_full,
|
||||
];
|
||||
});
|
||||
$userDepartmentIds = UserDepartment::where('rf_user_id', $user->id)
|
||||
->pluck('rf_department_id')
|
||||
->toArray();
|
||||
|
||||
return Inertia::render('Admin/Users/User', [
|
||||
'userData' => $userData,
|
||||
'roles' => $rolesData,
|
||||
'departments' => $departmentData,
|
||||
'userData' => $userData,
|
||||
'userRoleIds' => $userRoleIds,
|
||||
'userDepartmentIds' => $userDepartmentIds,
|
||||
'allRoles' => $this->allRoles(),
|
||||
'allDepartments' => $this->allDepartments(),
|
||||
]);
|
||||
}
|
||||
|
||||
public function update(User $user, Request $request)
|
||||
{
|
||||
abort_unless(auth()->user()->isAdmin(), 403);
|
||||
|
||||
$validated = $request->validate([
|
||||
'name' => 'required|string|max:255',
|
||||
'login' => 'required|string|max:255|unique:users,login,' . $user->id,
|
||||
'is_active' => 'required|boolean',
|
||||
'department_id' => 'required|integer|exists:departments,department_id',
|
||||
'departments' => 'array',
|
||||
'departments.*' => 'integer|exists:departments,department_id',
|
||||
'roles' => 'required|array|min:1',
|
||||
'roles.*' => 'integer|exists:roles,role_id',
|
||||
]);
|
||||
|
||||
$user->update([
|
||||
'name' => $validated['name'],
|
||||
'login' => $validated['login'],
|
||||
'is_active' => $validated['is_active'],
|
||||
'rf_department_id' => $validated['department_id'],
|
||||
]);
|
||||
|
||||
// Синхронизируем роли
|
||||
UserRole::where('rf_user_id', $user->id)->delete();
|
||||
foreach ($validated['roles'] as $i => $roleId) {
|
||||
UserRole::create([
|
||||
'rf_user_id' => $user->id,
|
||||
'rf_role_id' => $roleId,
|
||||
'is_active' => true,
|
||||
'is_default' => $i === 0,
|
||||
]);
|
||||
}
|
||||
|
||||
// Синхронизируем доп. отделения через updateOrCreate
|
||||
$newDeptIds = $validated['departments'] ?? [];
|
||||
UserDepartment::where('rf_user_id', $user->id)
|
||||
->whereNotIn('rf_department_id', $newDeptIds)
|
||||
->delete();
|
||||
foreach ($newDeptIds as $i => $deptId) {
|
||||
UserDepartment::updateOrCreate(
|
||||
['rf_user_id' => $user->id, 'rf_department_id' => $deptId],
|
||||
['is_favorite' => false, 'order' => $i]
|
||||
);
|
||||
}
|
||||
|
||||
return redirect('/admin/users/' . $user->id)->with('success', 'Данные сохранены');
|
||||
}
|
||||
|
||||
public function resetPassword(User $user, Request $request)
|
||||
{
|
||||
abort_unless(auth()->user()->isAdmin(), 403);
|
||||
|
||||
$request->validate([
|
||||
'password' => 'required|string|min:6|confirmed',
|
||||
]);
|
||||
|
||||
$user->update(['password' => Hash::make($request->password)]);
|
||||
|
||||
return redirect('/admin/users/' . $user->id)->with('success', 'Пароль изменён');
|
||||
}
|
||||
|
||||
private function allRoles(): array
|
||||
{
|
||||
return Role::all()->map(fn($r) => [
|
||||
'role_id' => $r->role_id,
|
||||
'name' => $r->name,
|
||||
])->toArray();
|
||||
}
|
||||
|
||||
private function allDepartments(): array
|
||||
{
|
||||
return Department::orderBy('name_full')->get()->map(fn($d) => [
|
||||
'department_id' => $d->department_id,
|
||||
'name_full' => $d->name_full,
|
||||
])->toArray();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,6 +5,8 @@ namespace App\Http\Controllers\Web;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Http\Resources\MedicalHistoryResource;
|
||||
use App\Models\Department;
|
||||
use App\Models\DepartmentMetrikaDefault;
|
||||
use App\Models\ObservableMedicalHistory;
|
||||
use App\Models\ReportDuty;
|
||||
use App\Models\ReportNurse;
|
||||
use App\Services\DateRangeService;
|
||||
@@ -15,6 +17,7 @@ use App\Services\NurseMedicalHistoryService;
|
||||
use App\Services\NurseReportService;
|
||||
use App\Services\UnifiedMedicalHistoryService;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Carbon;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Inertia\Inertia;
|
||||
|
||||
@@ -37,65 +40,306 @@ class DutyReportController extends Controller
|
||||
public function index(Request $request)
|
||||
{
|
||||
$user = Auth::user();
|
||||
$search = $request->get('search');
|
||||
$selectedUserId = $request->query('userId') ? (int) $request->query('userId') : null;
|
||||
$departmentId = $request->query('departmentId', $user->department->department_id);
|
||||
$department = Department::where('department_id', $departmentId)->firstOrFail();
|
||||
$bedsInDepartment = DepartmentMetrikaDefault::where('rf_department_id', $departmentId)
|
||||
->where('rf_metrika_item_id', 1)->first()->value ?? 0;
|
||||
$dateRange = $this->dateRangeService->getDateRangeFromRequest($request, $user);
|
||||
|
||||
// Проверяем, есть ли отчет за этот период
|
||||
$isRangeOneDay = $this->dateRangeService->isRangeOneDay($dateRange->startDate, $dateRange->endDate);
|
||||
$isPastPeriod = $this->dateRangeService->isPastPeriod($dateRange);
|
||||
$existsReport = ReportDuty::where('rf_department_id', $departmentId)
|
||||
->where('period_end', '>', $dateRange->startSql())
|
||||
$isCurrentPeriod = !$isPastPeriod;
|
||||
|
||||
// Всегда загружаем отчеты за период
|
||||
$reportsDuty = ReportDuty::where('rf_department_id', $departmentId)
|
||||
->where('period_start', '>=', $dateRange->startSql())
|
||||
->where('period_end', '<=', $dateRange->endSql())
|
||||
->exists();
|
||||
->orderBy('period_end', 'desc')
|
||||
->with(['unwantedEvents', 'doctor'])
|
||||
->get();
|
||||
|
||||
$hasReport = $existsReport && $isPastPeriod;
|
||||
$reportsNurse = ReportNurse::where('rf_department_id', $departmentId)
|
||||
->where('period_start', '>=', $dateRange->startSql())
|
||||
->where('period_end', '<=', $dateRange->endSql())
|
||||
->orderBy('period_end', 'desc')
|
||||
->get();
|
||||
|
||||
$hasDutyReport = $reportsDuty->count() > 0;
|
||||
$hasNurseReport = $reportsNurse->count() > 0;
|
||||
|
||||
$reportDutyIds = $reportsDuty->pluck('id')->toArray();
|
||||
$reportNurseIds = $reportsNurse->pluck('id')->toArray();
|
||||
|
||||
// dd($reportsDuty, $dateRange->endSql());
|
||||
|
||||
// Получаем пациентов (источник зависит от периода)
|
||||
if ($isCurrentPeriod) {
|
||||
// Для текущего периода - пациенты из МИС
|
||||
$patients = $this->medicalHistoryService->getGroupedHistories(
|
||||
$dateRange,
|
||||
$department->rf_mis_department_id,
|
||||
$search
|
||||
);
|
||||
|
||||
// Если есть отчет, загружаем из него дополнительные данные
|
||||
if ($hasDutyReport) {
|
||||
// Получаем нежелательные события и наблюдения из отчета
|
||||
$reportData = $this->getReportAdditionalData($reportsDuty);
|
||||
|
||||
// Добавляем эти данные к пациентам
|
||||
$patients = $this->mergeReportData($patients, $reportData);
|
||||
}
|
||||
|
||||
$nursePatients = $hasNurseReport
|
||||
? $this->nurseMedicalHistoryService->getGroupedHistories(
|
||||
$dateRange,
|
||||
$department->rf_mis_department_id,
|
||||
$reportNurseIds
|
||||
)
|
||||
: [];
|
||||
|
||||
$currentPatients = $patients['meta']['counts']['in_department'];
|
||||
$loaded = $bedsInDepartment > 0
|
||||
? round(($currentPatients * 100) / $bedsInDepartment)
|
||||
: 0;
|
||||
|
||||
$latestReport = $reportsDuty->first();
|
||||
|
||||
if ($hasReport) {
|
||||
$inDepartmentHistories = $this->dutyMedicalHistoryService->getDepartmentHistories($dateRange, $department->rf_mis_department_id);
|
||||
$plannedHistories = collect([ 'data' => [] ]);
|
||||
$emergencyHistories = collect([ 'data' => [] ]);
|
||||
$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);
|
||||
$reanimationHistories = collect([ 'data' => [] ]);
|
||||
} else if ($this->dateRangeService->isPastPeriod($dateRange)) {
|
||||
$inDepartmentHistories = collect([ 'data' => [] ]);
|
||||
$plannedHistories = collect([ 'data' => [] ]);
|
||||
$emergencyHistories = collect([ 'data' => [] ]);
|
||||
$recipientHistories = collect([ 'data' => [] ]);
|
||||
$dischargedHistories = collect([ 'data' => [] ]);
|
||||
$deceasedHistories = collect([ 'data' => [] ]);
|
||||
$transferredHistories = collect([ 'data' => [] ]);
|
||||
$reanimationHistories = collect([ 'data' => [] ]);
|
||||
} else {
|
||||
$patients = $this->medicalHistoryService->getGroupedHistories($dateRange, $department->rf_mis_department_id);
|
||||
// Для прошедшего периода - данные из отчета
|
||||
$patients = $hasDutyReport
|
||||
? $this->dutyMedicalHistoryService->getGroupedHistories(
|
||||
$dateRange,
|
||||
$department->rf_mis_department_id,
|
||||
$reportDutyIds,
|
||||
$search
|
||||
)
|
||||
: $this->getEmptyPatientsData();
|
||||
|
||||
$nursePatients = $hasNurseReport
|
||||
? $this->nurseMedicalHistoryService->getGroupedHistories(
|
||||
$dateRange,
|
||||
$department->rf_mis_department_id,
|
||||
$reportNurseIds
|
||||
)
|
||||
: [];
|
||||
|
||||
$latestReport = $reportsDuty->first();
|
||||
|
||||
if ($latestReport && $hasDutyReport) {
|
||||
$currentPatients = $patients['meta']['counts']['in_department'];
|
||||
$loaded = $latestReport->getLoadedDepartmentAttribute($currentPatients);
|
||||
} else {
|
||||
$loaded = 0;
|
||||
}
|
||||
}
|
||||
|
||||
return Inertia::render('Report/Index', [
|
||||
'department' => $department,
|
||||
'patients' => $patients,
|
||||
'departmentInfo' => [
|
||||
// TODO: Добавить вывод информации из шапки
|
||||
],
|
||||
'nursePatients' => $nursePatients,
|
||||
'latestReport' => $latestReport ?? null,
|
||||
'canSaveReport' => $isRangeOneDay && $user->currentRoleCan('report.create'),
|
||||
'canEditPastReport' => $user->currentRoleCan('report.edit.past'),
|
||||
'canSaveNurseReport' => $isRangeOneDay && $user->currentRoleCan('nurse.report.create'),
|
||||
'stats' => $this->prepareStats($patients, $nursePatients, $loaded, $bedsInDepartment),
|
||||
'dates' => [
|
||||
$dateRange->startDate->getTimestampMs(),
|
||||
$dateRange->endDate->getTimestampMs(),
|
||||
]
|
||||
],
|
||||
'selectedUserId' => $selectedUserId,
|
||||
'selectedDepartmentId' => (int) $departmentId,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Сохранение отчета от роли мед. сестра
|
||||
* Получает дополнительные данные из отчета (нежелательные события, наблюдения)
|
||||
*/
|
||||
private function getReportAdditionalData($reportsDuty): array
|
||||
{
|
||||
$unwantedEvents = [];
|
||||
$observations = [];
|
||||
|
||||
foreach ($reportsDuty as $report) {
|
||||
// Нежелательные события
|
||||
foreach ($report->unwantedEvents as $event) {
|
||||
$unwantedEvents[] = [
|
||||
...$event->toArray(),
|
||||
];
|
||||
}
|
||||
|
||||
// Наблюдения (если есть связь)
|
||||
if ($report->relationLoaded('observations') || $report->observations) {
|
||||
foreach ($report->observations as $observation) {
|
||||
$observations[] = [
|
||||
...$observation->toArray(),
|
||||
];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return [
|
||||
'unwanted_events' => $unwantedEvents,
|
||||
'observations' => $observations
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Объединяет данные пациентов из МИС с данными из отчета
|
||||
*/
|
||||
private function mergeReportData(array $patients, array $reportData): array
|
||||
{
|
||||
// Группируем нежелательные события по отчетам
|
||||
// $eventsByPatient = [];
|
||||
// foreach ($reportData['unwanted_events'] as $event) {
|
||||
// $reportId = $event['report_duty_id'];
|
||||
// if (!isset($eventsByPatient[$reportId])) {
|
||||
// $eventsByPatient[$reportId] = [];
|
||||
// }
|
||||
// $eventsByPatient[$reportId][] = $event;
|
||||
// }
|
||||
|
||||
// Группируем наблюдения по пациентам
|
||||
$observationsByPatient = [];
|
||||
foreach ($reportData['observations'] as $observation) {
|
||||
$patientId = $observation['patient_id'];
|
||||
if (!isset($observationsByPatient[$patientId])) {
|
||||
$observationsByPatient[$patientId] = [];
|
||||
}
|
||||
$observationsByPatient[$patientId][] = $observation;
|
||||
}
|
||||
|
||||
// Добавляем данные из отчета к каждому пациенту
|
||||
foreach ($patients['data'] as &$patient) {
|
||||
$patientId = $patient['original_id'] ?? $patient['id'] ?? null;
|
||||
|
||||
// Может быть позже пригодится
|
||||
// if ($patientId && isset($eventsByPatient[$patientId])) {
|
||||
// $patient['unwanted_events'] = $eventsByPatient[$patientId];
|
||||
// } else {
|
||||
// $patient['unwanted_events'] = [];
|
||||
// }
|
||||
|
||||
if ($patientId && isset($observationsByPatient[$patientId])) {
|
||||
$patient['observations'] = $observationsByPatient[$patientId];
|
||||
} else {
|
||||
$patient['observations'] = [];
|
||||
}
|
||||
}
|
||||
|
||||
return $patients;
|
||||
}
|
||||
|
||||
/**
|
||||
* Получает данные из сестринского отчета
|
||||
*/
|
||||
private function getNurseReportAdditionalData($reportsNurse): array
|
||||
{
|
||||
$nurseData = [];
|
||||
|
||||
foreach ($reportsNurse as $report) {
|
||||
// Загружаем необходимые данные из сестринского отчета
|
||||
// Например, наблюдения медсестер, процедуры и т.д.
|
||||
if ($report->relationLoaded('nurseObservations')) {
|
||||
$nurseData = array_merge($nurseData, $report->nurseObservations->toArray());
|
||||
}
|
||||
}
|
||||
|
||||
return $nurseData;
|
||||
}
|
||||
|
||||
/**
|
||||
* Возвращает пустую структуру данных для пациентов
|
||||
*/
|
||||
private function getEmptyPatientsData(): array
|
||||
{
|
||||
return [
|
||||
'data' => [],
|
||||
'meta' => [
|
||||
'total' => 0,
|
||||
'sortBy' => 'ingoing_date',
|
||||
'sortOrder' => 'desc',
|
||||
'counts' => [
|
||||
'in_department' => 0,
|
||||
'recipient' => 0,
|
||||
'discharged' => 0,
|
||||
'deceased' => 0,
|
||||
'urgent' => 0,
|
||||
'planned' => 0,
|
||||
'reanimations' => 0,
|
||||
'surgical_planned' => 0,
|
||||
'surgical_urgent' => 0,
|
||||
]
|
||||
]
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Подготавливает статистику для отображения на фронтенде
|
||||
*/
|
||||
private function prepareStats(array $patients, array $nursePatients, int $loaded, ?int $bedsInDepartment): array
|
||||
{
|
||||
return [
|
||||
'nurse' => [
|
||||
'current' => empty($nursePatients) ? 0 : ($nursePatients['meta']['counts']['in_department'] ?? 0),
|
||||
'recipient' => empty($nursePatients) ? 0 : ($nursePatients['meta']['counts']['recipient'] ?? 0),
|
||||
'discharged' => empty($nursePatients) ? 0 : ($nursePatients['meta']['counts']['discharged'] ?? 0),
|
||||
],
|
||||
'duty' => [
|
||||
'beds' => $bedsInDepartment ?? 0,
|
||||
'loaded' => $loaded,
|
||||
'current' => $patients['meta']['counts']['in_department'] ?? 0,
|
||||
'recipient' => $patients['meta']['counts']['recipient'] ?? 0,
|
||||
'discharged' => ($patients['meta']['counts']['discharged'] ?? 0) + ($patients['meta']['counts']['deceased'] ?? 0),
|
||||
'deceased' => $patients['meta']['counts']['deceased'] ?? 0,
|
||||
'surgical_planned' => $patients['meta']['counts']['surgical_planned'] ?? 0,
|
||||
'surgical_urgent' => $patients['meta']['counts']['surgical_urgent'] ?? 0,
|
||||
]
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Сохранение отчета
|
||||
* @return \Illuminate\Http\RedirectResponse
|
||||
*/
|
||||
public function store(Request $request)
|
||||
{
|
||||
abort_if(!auth()->user()->currentRoleCan('report.create'), 403);
|
||||
|
||||
$user = auth()->user();
|
||||
$observables = $request->get('observables', []);
|
||||
$unwantedEvents = $request->get('unwanted_events', []);
|
||||
$selectedUserId = $request->get('userId') ? (int) $request->get('userId') : null;
|
||||
$selectedDepartmentId = $request->get('departmentId') ? (int) $request->get('departmentId') : null;
|
||||
$staff = (int) $request->get('staff', 0);
|
||||
|
||||
$dateRange = $this->dateRangeService->getDateRangeFromRequest($request, $user);
|
||||
$report = $this->dutyReportService->saveReport($dateRange);
|
||||
$this->dutyReportService->saveSnapshot($dateRange, $report);
|
||||
$report = $this->dutyReportService->saveReport($dateRange, null, $selectedUserId, $selectedDepartmentId);
|
||||
$stats = $this->dutyReportService->saveSnapshot($dateRange, $report, null, auth()->id());
|
||||
$this->dutyReportService->saveObservables($observables, $report);
|
||||
$this->dutyReportService->saveUnwantedEvents($unwantedEvents, $report);
|
||||
|
||||
$this->dutyReportService->saveMetrics($stats, $report, $staff);
|
||||
|
||||
return redirect()->back();
|
||||
}
|
||||
|
||||
public function closeObservation(Request $request)
|
||||
{
|
||||
$user = auth()->user();
|
||||
$dateRange = $this->dateRangeService->getDateRangeFromRequest($request, $user);
|
||||
|
||||
$observable = $request->get('observable');
|
||||
$observableId = $observable['id'] ?? null;
|
||||
|
||||
if ($observableId === null) return response()->json('Observable not found', 404);
|
||||
|
||||
$observable = ObservableMedicalHistory::find($observableId);
|
||||
$observable->update([
|
||||
'observable_out' => $dateRange->endDate,
|
||||
'out_reason' => 'Закрыто пользователем'
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,12 +18,10 @@ class IndexController extends Controller
|
||||
->where('rf_metrika_group_id', $metriks->metrika_group_id)
|
||||
->get();
|
||||
|
||||
$fillableModel =
|
||||
|
||||
$departments = Department::all();
|
||||
|
||||
return Inertia::render('Report/Index', [
|
||||
'depatments' => $departments,
|
||||
'departments' => $departments,
|
||||
'metriks' => $metriksItems->map(fn ($item) => [
|
||||
'metrika_group_id' => $item->group->metrika_group_id,
|
||||
'metrika_group_name' => $item->group->name,
|
||||
|
||||
@@ -31,6 +31,7 @@ class NurseReportController extends Controller
|
||||
public function index(Request $request)
|
||||
{
|
||||
$user = Auth::user();
|
||||
$selectedUserId = $request->query('userId') ? (int) $request->query('userId') : null;
|
||||
$departmentId = $request->query('departmentId', $user->department->department_id);
|
||||
$department = Department::where('department_id', $departmentId)->firstOrFail();
|
||||
$dateRange = $this->dateRangeService->getDateRangeFromRequest($request, $user);
|
||||
@@ -66,8 +67,22 @@ class NurseReportController extends Controller
|
||||
|
||||
$data = $this->unifiedMedicalHistoryService->getGroupedHistories($dateRange, $department->rf_mis_department_id);
|
||||
|
||||
$currentReport = ReportNurse::where('rf_department_id', $departmentId)
|
||||
->where('period_start', '>=', $dateRange->startSql())
|
||||
->where('period_end', '<=', $dateRange->endSql())
|
||||
->orderBy('period_end', 'desc')
|
||||
->first();
|
||||
|
||||
$isRangeOneDay = $this->dateRangeService->isRangeOneDay($dateRange->startDate, $dateRange->endDate);
|
||||
|
||||
return Inertia::render('Nurse/Report/Index', [
|
||||
'patients' => $data,
|
||||
'reportNurseId' => $currentReport?->id,
|
||||
'canSaveReport' => $isRangeOneDay && $user->currentRoleCan('nurse.report.create'),
|
||||
'canEditPastReport' => $user->currentRoleCan('nurse.report.edit.past'),
|
||||
'department' => $department,
|
||||
'selectedUserId' => $selectedUserId,
|
||||
'selectedDepartmentId' => (int) $departmentId,
|
||||
'dates' => [
|
||||
$dateRange->startDate->getTimestampMs(),
|
||||
$dateRange->endDate->getTimestampMs(),
|
||||
@@ -81,11 +96,15 @@ class NurseReportController extends Controller
|
||||
*/
|
||||
public function store(Request $request)
|
||||
{
|
||||
abort_if(!auth()->user()->currentRoleCan('nurse.report.create'), 403);
|
||||
|
||||
$user = auth()->user();
|
||||
$selectedUserId = $request->input('userId') ? (int) $request->input('userId') : null;
|
||||
$departmentId = $request->input('departmentId') ? (int) $request->input('departmentId') : null;
|
||||
|
||||
$dateRange = $this->dateRangeService->getDateRangeFromRequest($request, $user);
|
||||
$report = $this->nurseReportService->saveReport($dateRange);
|
||||
$this->nurseReportService->saveSnapshot($dateRange, $report);
|
||||
$report = $this->nurseReportService->saveReport($dateRange, null, $selectedUserId, $departmentId);
|
||||
$this->nurseReportService->saveSnapshot($dateRange, $report, null, auth()->id());
|
||||
|
||||
return redirect()->back();
|
||||
}
|
||||
|
||||
@@ -23,27 +23,30 @@ class StatisticController extends Controller
|
||||
|
||||
$queryStartDate = $request->query('startAt');
|
||||
$queryEndDate = $request->query('endAt');
|
||||
[$startDate, $endDate] = $this->dateService->getStatisticsDateRange($user, $queryStartDate, $queryEndDate);
|
||||
$isRangeOneDay = $this->dateService->isRangeOneDay($startDate, $endDate);
|
||||
$dateRange = $this->dateService->getDateRangeFromRequest($request, $user);
|
||||
$isRangeOneDay = $this->dateService->isRangeOneDay($dateRange->startDate, $dateRange->endDate);
|
||||
|
||||
// Генерируем ключ кэша на основе параметров запроса
|
||||
// $cacheKey = $this->generateCacheKey($user, $startDate, $endDate, $isRangeOneDay);
|
||||
|
||||
// Получаем данные из кэша или вычисляем
|
||||
$finalData = $this->statisticsService->getStatisticsData($user, $startDate, $endDate, $isRangeOneDay);
|
||||
$finalData = $this->statisticsService->getStatisticsData($user, $dateRange->startDate, $dateRange->endDate, $isRangeOneDay);
|
||||
|
||||
$isHeadOrAdmin = $user->isAdmin() || $user->isHeadOfDepartment();
|
||||
$date = $isHeadOrAdmin ? [
|
||||
$this->dateService->parseDate($isRangeOneDay ? $endDate : $startDate)->getTimestampMs(),
|
||||
$this->dateService->parseDate($endDate)->getTimestampMs(),
|
||||
] : $this->dateService->parseDate($endDate)->getTimestampMs();
|
||||
$isHeadOrAdmin = $user->isSeniorStaff();
|
||||
// $date = $isHeadOrAdmin ? [
|
||||
// $this->dateService->parseDate($isRangeOneDay ? $dateRange->endDate : $dateRange->startDate)->getTimestampMs(),
|
||||
// $this->dateService->parseDate($dateRange->endDate)->getTimestampMs(),
|
||||
// ] : $this->dateService->parseDate($dateRange->endDate)->getTimestampMs();
|
||||
|
||||
return Inertia::render('Statistic/Index', [
|
||||
'data' => $finalData['data'],
|
||||
'totalsByType' => $finalData['totalsByType'],
|
||||
'grandTotals' => $finalData['grandTotals'],
|
||||
'isHeadOrAdmin' => $isHeadOrAdmin,
|
||||
'date' => $date,
|
||||
'date' => [
|
||||
$dateRange->startDate->getTimestampMs(),
|
||||
$dateRange->endDate->getTimestampMs(),
|
||||
],
|
||||
'isOneDay' => $isRangeOneDay,
|
||||
'recipientPlanOfYear' => $finalData['recipientPlanOfYear'],
|
||||
]);
|
||||
|
||||
Reference in New Issue
Block a user