This commit is contained in:
Dwi Swandhana
2026-04-08 05:44:57 +07:00
parent 68f6ecc98e
commit 9751007863
4 changed files with 151 additions and 18 deletions
+109 -16
View File
@@ -719,9 +719,13 @@ class DokterController extends Controller
protected function shouldMarkAsCritical(Request $request): bool
{
$flag = strtolower((string) $request->input('nilai_kritis', '0'));
$master = (string) $request->input('master_mikro', '');
$periksaId = $request->input('periksa_id');
$periksa = !empty($periksaId)
? Periksa::select('nm_spesimen')->find($periksaId)
: null;
$nmSpesimen = strtoupper(trim((string) ($periksa->nm_spesimen ?? '')));
if ($master !== 'buku03') {
if (!str_contains($nmSpesimen, 'DARAH')) {
return false;
}
@@ -759,34 +763,119 @@ class DokterController extends Controller
}
protected function getPendingCriticalValueItems()
{
return CriticalValueSample::whereNull('followed_up_at')
return $this->appendCriticalValueTatMeta(
CriticalValueSample::whereNull('followed_up_at')
->orderBy('critical_set_at', 'asc')
->get();
->get()
);
}
protected function getFollowedCriticalValueItems()
protected function resolveCriticalValueReportRange(Request $request): array
{
return CriticalValueSample::whereNotNull('followed_up_at')
$defaultStart = Carbon::now()->startOfMonth()->toDateString();
$defaultEnd = Carbon::now()->endOfMonth()->toDateString();
$startDate = trim((string) $request->query('start_date', $defaultStart));
$endDate = trim((string) $request->query('end_date', $defaultEnd));
try {
$start = Carbon::createFromFormat('Y-m-d', $startDate)->startOfDay();
} catch (\Throwable $e) {
$start = Carbon::createFromFormat('Y-m-d', $defaultStart)->startOfDay();
$startDate = $defaultStart;
}
try {
$end = Carbon::createFromFormat('Y-m-d', $endDate)->endOfDay();
} catch (\Throwable $e) {
$end = Carbon::createFromFormat('Y-m-d', $defaultEnd)->endOfDay();
$endDate = $defaultEnd;
}
if ($start->gt($end)) {
[$start, $end] = [$end->copy()->startOfDay(), $start->copy()->endOfDay()];
$startDate = $start->toDateString();
$endDate = $end->toDateString();
}
return [
'start_date' => $startDate,
'end_date' => $endDate,
'start_at' => $start,
'end_at' => $end,
];
}
protected function getFollowedCriticalValueItems(?Carbon $startAt = null, ?Carbon $endAt = null)
{
$query = CriticalValueSample::whereNotNull('followed_up_at');
if ($startAt !== null) {
$query->where('followed_up_at', '>=', $startAt);
}
if ($endAt !== null) {
$query->where('followed_up_at', '<=', $endAt);
}
return $this->appendCriticalValueTatMeta(
$query
->orderBy('followed_up_at', 'desc')
->limit(100)
->get();
->get()
);
}
protected function appendCriticalValueTatMeta($items)
{
return $items->map(function ($item) {
$item->tat_minutes = null;
$item->tat_duration_label = '-';
$item->tat_status_label = '-';
if (!empty($item->critical_set_at) && !empty($item->followed_up_at)) {
$criticalSetAt = Carbon::parse($item->critical_set_at);
$followedUpAt = Carbon::parse($item->followed_up_at);
$diffMinutes = $criticalSetAt->diffInMinutes($followedUpAt);
$item->tat_minutes = $diffMinutes;
$item->tat_duration_label = $this->formatTatDuration($diffMinutes);
$item->tat_status_label = $diffMinutes <= 30 ? 'Memenuhi TAT' : 'Tidak Memenuhi TAT';
}
return $item;
});
}
protected function formatTatDuration(int $totalMinutes): string
{
$hours = intdiv($totalMinutes, 60);
$minutes = $totalMinutes % 60;
if ($hours > 0) {
return $hours.' jam '.$minutes.' menit';
}
return $minutes.' menit';
}
public function criticalValueNotifications(Request $request)
{
$highlightId = $request->query('highlight');
$reportRange = $this->resolveCriticalValueReportRange($request);
$items = $this->getPendingCriticalValueItems();
$followedItems = $this->getFollowedCriticalValueItems();
$followedItems = $this->getFollowedCriticalValueItems($reportRange['start_at'], $reportRange['end_at']);
return view('notifications.critical-values', [
'items' => $items,
'followedItems' => $followedItems,
'highlightId' => $highlightId,
'startDate' => $reportRange['start_date'],
'endDate' => $reportRange['end_date'],
]);
}
public function criticalValueNotificationExport(Request $request)
{
$type = $request->query('type', 'pending');
$isFollowed = $type === 'followed';
$rows = $isFollowed ? $this->getFollowedCriticalValueItems() : $this->getPendingCriticalValueItems();
$reportRange = $this->resolveCriticalValueReportRange($request);
$rows = $isFollowed
? $this->getFollowedCriticalValueItems($reportRange['start_at'], $reportRange['end_at'])
: $this->getPendingCriticalValueItems();
$filename = $isFollowed
? 'notifikasi-nilai-kritis-riwayat-'.Carbon::now()->format('Ymd_His').'.xlsx'
: 'notifikasi-nilai-kritis-belum-dilaporkan-'.Carbon::now()->format('Ymd_His').'.xlsx';
@@ -807,6 +896,8 @@ class DokterController extends Controller
'Diset Oleh',
'Waktu Ditindaklanjuti',
'Ditindaklanjuti Oleh',
'Selisih Waktu',
'Status TAT',
'Status Tindak Lanjut',
'Metode',
'Penerima Laporan',
@@ -836,6 +927,8 @@ class DokterController extends Controller
$item->critical_set_by_name ?? '-',
$item->followed_up_at ? Carbon::parse($item->followed_up_at)->format('d-m-Y H:i:s') : '-',
$item->followed_up_by_name ?? '-',
$item->tat_duration_label ?? '-',
$item->tat_status_label ?? '-',
$statusLabel,
$item->follow_up_method ?? '-',
$item->follow_up_recipient ?? '-',
@@ -844,7 +937,7 @@ class DokterController extends Controller
$rowNumber++;
}
foreach (range('A', 'N') as $col) {
foreach (range('A', 'P') as $col) {
$sheet->getColumnDimension($col)->setAutoSize(true);
}
@@ -943,7 +1036,7 @@ class DokterController extends Controller
$updated = Periksa::where('id', $id)->update([
'noloket' => null,
'status' => 'Batal',
'status' => 'Dibatalkan (Arsip)',
]);
if (!$updated) {
@@ -1004,7 +1097,7 @@ class DokterController extends Controller
Periksa::where('id', $idperiksa)->orWhere('nofoto', $idperiksa)->update([
'keterangan' => $val01,
'admin' => Session('nama'),
'status' => 'Batal'
'status' => 'Dibatalkan (Arsip)'
]);
if ($pacsaddr == '' OR $pacsaddr === null){
$pesan = '';
@@ -3546,9 +3639,9 @@ class DokterController extends Controller
if ($status == '' OR is_null($status)){
$status = 'new';
} else {
$cekbatal = explode('batalkan dengan alasan ', $status);
$cekbatal = explode('batal', $status);
if (isset($cekbatal[1])){
$keterangan = $cekbatal[1];
$keterangan = $status;
$status = 'Batal';
} else {
if ($status == 'Arsip' OR $status == 'Selesai'){
@@ -3592,9 +3685,9 @@ class DokterController extends Controller
if ($status == '' OR is_null($status)){
$status = 'new';
} else {
$cekbatal = explode('batalkan dengan alasan ', $status);
$cekbatal = explode('batal', $status);
if (isset($cekbatal[1])){
$keterangan = $cekbatal[1];
$keterangan = $status;
$status = 'Batal';
} else {
if ($status == 'Arsip' OR $status == 'Selesai'){
@@ -2376,7 +2376,7 @@
<button type="button" id="btnsavedraft" class="btn btn-success pull-right">Save as Draft</button>
</div>
@if (Session('previlage') == 'supervisor' OR Session('previlage') == 'developer')
<div class="col-auto">
<div class="col-auto" id="nilai_kritis_wrapper" style="display: none;">
<div class="form-check mb-2">
<input class="form-check-input" type="checkbox" id="nilai_kritis" name="nilai_kritis">
<label class="form-check-label" for="nilai_kritis">
@@ -5028,6 +5028,7 @@
$("#otheras").val(dataRecord.ppdsas);
$("#kave").val(dataRecord.kd_spesimen);
$("#mas").val(dataRecord.nm_spesimen);
window.syncNilaiKritisVisibility(dataRecord.nm_spesimen);
$("#berat").val(dataRecord.berat);
$("#klinis").val(dataRecord.klinis);
$("#klinisi").html(dataRecord.klinisi);
@@ -6039,6 +6040,16 @@
$("#btnopenmodalcancel").click(function() {
$("#modalpembatalan").modal('show');
});
window.syncNilaiKritisVisibility = function(spesimen) {
var normalized = ((spesimen || '') + '').trim().toUpperCase();
var isDarah = normalized.indexOf('DARAH') !== -1;
if (isDarah) {
$('#nilai_kritis_wrapper').show();
} else {
$('#nilai_kritis').prop('checked', false);
$('#nilai_kritis_wrapper').hide();
}
}
$("#btnshowtemplate").click(function() {
$('#divtemplate').show();
});
@@ -112,10 +112,26 @@
<div class="card-body">
<div class="d-flex justify-content-between align-items-center mb-3">
<h5 class="card-title mb-0">Riwayat Nilai Kritis Yang Sudah Ditindaklanjuti</h5>
<a href="{{ route('criticalValueNotificationExport', ['type' => 'followed']) }}" class="btn btn-success btn-sm">
<a href="{{ route('criticalValueNotificationExport', ['type' => 'followed', 'start_date' => $startDate, 'end_date' => $endDate]) }}" class="btn btn-success btn-sm">
Export Excel
</a>
</div>
<form method="GET" action="{{ route('criticalValueNotifications') }}" class="mb-3">
<div class="form-row align-items-end">
<div class="form-group col-md-3">
<label for="start_date">Start Date Report</label>
<input type="date" id="start_date" name="start_date" class="form-control" value="{{ $startDate }}">
</div>
<div class="form-group col-md-3">
<label for="end_date">End Date Report</label>
<input type="date" id="end_date" name="end_date" class="form-control" value="{{ $endDate }}">
</div>
<div class="form-group col-md-6">
<button type="submit" class="btn btn-primary btn-sm">Tampilkan</button>
<a href="{{ route('criticalValueNotifications') }}" class="btn btn-secondary btn-sm">Reset</a>
</div>
</div>
</form>
@if($followedItems->isEmpty())
<div class="alert alert-secondary mb-0">Belum ada riwayat tindak lanjut.</div>
@else
@@ -131,6 +147,8 @@
<th>Spesimen</th>
<th>Waktu Set Nilai Kritis</th>
<th>Waktu Ditindaklanjuti</th>
<th>Selisih Waktu</th>
<th>Status TAT</th>
<th>Aksi</th>
</tr>
</thead>
@@ -155,6 +173,16 @@
<br><small>oleh {{ $item->followed_up_by_name }}</small>
@endif
</td>
<td>{{ $item->tat_duration_label ?? '-' }}</td>
<td>
@if(($item->tat_status_label ?? '-') === 'Memenuhi TAT')
<span class="badge badge-success">{{ $item->tat_status_label }}</span>
@elseif(($item->tat_status_label ?? '-') === 'Tidak Memenuhi TAT')
<span class="badge badge-danger">{{ $item->tat_status_label }}</span>
@else
<span class="badge badge-secondary">-</span>
@endif
</td>
<td>
@php
$status = $item->follow_up_status ?? '';
@@ -226,6 +226,7 @@
}
},
{ text: 'Acc.No', datafield: 'nofoto', width: 100, cellsalign: 'left', align: 'center' },
{ text: 'Order', datafield: 'tlsreques', width: 200, cellsalign: 'left', align: 'center' },
{ text: 'No.RM', datafield: 'tlsnoregister', width: 100, cellsalign: 'left', align: 'center' },
{ text: 'Name', datafield: 'tlsnama', width: 150, cellsalign: 'left', align: 'center' },
{ text: 'Gender', datafield: 'tlsjk', filtertype: 'checkedlist', width: 50, cellsalign: 'left', align: 'center' },