From 30e39875c005580cefa2bdfe190f03922599b395 Mon Sep 17 00:00:00 2001 From: Dwi Swandhana Date: Sun, 19 Jul 2026 20:47:08 +0700 Subject: [PATCH] update --- .../app/Http/Controllers/DokterController.php | 77 +++++++++++----- .../app/Http/Controllers/ReportController.php | 8 ++ htdocs/app/Services/AstmMessageService.php | 89 +++++++++++++++---- htdocs/resources/views/admin/report.blade.php | 4 + 4 files changed, 137 insertions(+), 41 deletions(-) diff --git a/htdocs/app/Http/Controllers/DokterController.php b/htdocs/app/Http/Controllers/DokterController.php index 1f89a8a9..520dc475 100644 --- a/htdocs/app/Http/Controllers/DokterController.php +++ b/htdocs/app/Http/Controllers/DokterController.php @@ -549,30 +549,50 @@ class DokterController extends Controller foreach($cekganda as $rcloning){ $nofotocloning = $rcloning->nofoto; $dlpcloning = $rcloning->dlp ?? 'Kultur'; - if (is_array($value)) { - KomponenJawaban::updateOrCreate( - [ - 'accnumber' => $nofotocloning, - 'komponen' => $yangperludicloning, - ], - [ - 'isidata' => json_encode($value), - 'template' => $dlpcloning, - 'created_by' => session('nama'), - ] - ); + $cekada = KomponenJawaban::where('accnumber', $nofotocloning)->where('komponen', $yangperludicloning)->first(); + if ($cekada){ + } else { - KomponenJawaban::updateOrCreate( - [ - 'accnumber' => $nofotocloning, - 'komponen' => $yangperludicloning, - ], - [ - 'isidata' => $value, - 'template' => $dlpcloning, - 'created_by' => session('nama'), - ] - ); + if (is_array($value)) { + KomponenJawaban::updateOrCreate( + [ + 'accnumber' => $nofotocloning, + 'komponen' => $yangperludicloning, + ], + [ + 'isidata' => json_encode($value), + 'template' => $dlpcloning, + 'created_by' => session('nama'), + ] + ); + Riwayat::create([ + 'nofoto' => $nofotocloning, + 'jawaban' => json_encode($value), + 'inputor' => Session('nama'), + 'keterangan' => 'Clone Data '.$yangperludicloning.' Dari ('.$nofoto.')', + 'verifikasi' => '', + ]); + } else { + KomponenJawaban::updateOrCreate( + [ + 'accnumber' => $nofotocloning, + 'komponen' => $yangperludicloning, + ], + [ + 'isidata' => $value, + 'template' => $dlpcloning, + 'created_by' => session('nama'), + ] + ); + Riwayat::create([ + 'nofoto' => $nofotocloning, + 'jawaban' => $value, + 'inputor' => Session('nama'), + 'keterangan' => 'Clone Data '.$yangperludicloning.' Dari ('.$nofoto.')', + 'verifikasi' => '', + ]); + } + } } } @@ -3875,6 +3895,11 @@ class DokterController extends Controller $urlhasil = url('/').'/hasil/'.$rows->nofoto; $status = $rows->status; $keterangan = ''; + $preliminary = DB::table('riwayatjawaban') + ->where('nofoto', $rows->nofoto) + ->where('keterangan', 'Preliminary Results') + ->orderBy('created_at', 'DESC') + ->first(); if ($status == '' OR is_null($status)){ $status = 'new'; } else { @@ -3893,7 +3918,7 @@ class DokterController extends Controller } } } - $data[] = array( + $rowData = array( 'nofoto' => $rows->nofoto, 'nolab' => $rows->orderid, 'norm' => $rows->norm, @@ -3906,7 +3931,11 @@ class DokterController extends Controller 'spesimen' => $rows->nm_spesimen, 'rawdata' => self::genSurat($rows->id, 'dengan kop'), 'critical' => $critical, + 'preliminary_date' => $preliminary->created_at ?? null, + 'preliminary_spv' => $preliminary->inputor ?? null, + 'preliminary_html' => $preliminary->jawaban ?? null, ); + $data[] = $rowData; } } return response()->json(['data' => $data], 201); diff --git a/htdocs/app/Http/Controllers/ReportController.php b/htdocs/app/Http/Controllers/ReportController.php index aa67b7d4..fc8a7c73 100644 --- a/htdocs/app/Http/Controllers/ReportController.php +++ b/htdocs/app/Http/Controllers/ReportController.php @@ -553,6 +553,13 @@ class ReportController extends Controller ->whereIn('id', array_unique($poli_ids)) ->get() ->keyBy('id'); + $preliminaries = DB::table('riwayatjawaban') + ->select('nofoto', 'created_at') + ->whereIn('nofoto', array_unique($acc)) + ->where('keterangan', 'Preliminary Results') + ->orderBy('created_at', 'DESC') + ->get() + ->groupBy('nofoto'); foreach ($hasil as $row) { $k = $komponen[$row->nofoto] ?? collect([]); $row->id_bakteri01 = optional($k->firstWhere('komponen','id_bakteri01'))->isidata; @@ -567,6 +574,7 @@ class ReportController extends Controller ->implode('; '); $row->filefoto = "nofoto)."'>$row->nofoto"; + $row->tgl_preliminary = optional(($preliminaries[$row->nofoto] ?? collect([]))->first())->created_at; $p = $poli[$row->poli_id] ?? null; $row->subpoli = $p->subpoli ?? null; $row->modaliti2 = $this->resolveTatTargetDays($p->modaliti2 ?? '1'); diff --git a/htdocs/app/Services/AstmMessageService.php b/htdocs/app/Services/AstmMessageService.php index 7661b202..8527eeac 100644 --- a/htdocs/app/Services/AstmMessageService.php +++ b/htdocs/app/Services/AstmMessageService.php @@ -240,6 +240,51 @@ class AstmMessageService return explode('^', $value)[0] ?: null; } + protected function normalizeAstmRecordLines(string $raw): string + { + $normalized = str_replace(["\r\n", "\r"], "\n", $raw); + + if (str_contains($normalized, "\n")) { + return $normalized; + } + + $fields = explode('|', $normalized); + $records = []; + $current = []; + + foreach ($fields as $index => $field) { + $isSegmentStart = $this->isAstmSegmentStart($fields, $index); + + if ($isSegmentStart && !empty($current)) { + $records[] = implode('|', $current); + $current = []; + } + + $current[] = $field; + } + + if (!empty($current)) { + $records[] = implode('|', $current); + } + + return !empty($records) ? implode("\n", $records) : $normalized; + } + protected function isAstmSegmentStart(array $fields, int $index): bool + { + $field = $fields[$index] ?? ''; + + if ($field === 'H') { + return $index === 0; + } + + if (!in_array($field, ['P', 'O', 'R', 'L'], true)) { + return false; + } + + $next = $fields[$index + 1] ?? null; + + return $next !== null && preg_match('/^\d+$/', (string) $next) === 1; + } protected function processBDAstmResponse(string $raw, $data): bool { try { @@ -602,7 +647,7 @@ class AstmMessageService } public function processAstmMessagesgenExpert($response, $alat) { - $normalizedData = str_replace(["\r\n", "\r"], "\n", $response); + $normalizedData = $this->normalizeAstmRecordLines($response); $segments = explode("\n", $normalizedData); $patient_id = ''; @@ -621,9 +666,12 @@ class AstmMessageService // 1. Parsing Pasien if ($recordType === 'P') { - $patient_id = !empty($cekdata[3]) ? $cekdata[3] : (!empty($cekdata[4]) ? $cekdata[4] : ''); + $rawPatientId = $cekdata[2] ?? ($cekdata[3] ?? ''); + $patient_id = trim(str_replace(['\R\\', '\\R\\', '\\'], '', $rawPatientId)); - $raw_name = isset($cekdata[5]) ? trim(str_replace('^', ' ', $cekdata[5])) : ''; + $raw_name = !empty($cekdata[4]) + ? trim(str_replace('^', ' ', $cekdata[4])) + : (isset($cekdata[5]) ? trim(str_replace('^', ' ', $cekdata[5])) : ''); $patient_name = !empty(trim($raw_name)) ? $raw_name : $patient_id; } @@ -650,24 +698,28 @@ class AstmMessageService return trim($val) !== ''; })); - $target_name = ''; $metric_type = 'Result'; + $target_parts = $target_match; + $last_part = end($target_parts); - // Jika string test_info mengandung 'Ct' atau 'EndPt', elemen terakhir adalah metrik, - // dan elemen sebelum terakhir adalah nama targetnya. - if (strpos($rsegmen, 'Ct|') !== false) { + // Jika string test_info mengandung metrik, elemen terakhir adalah metrik, + // dan elemen sebelumnya adalah nama target. + if ($last_part === 'Ct') { $metric_type = 'Ct'; - // Mengambil nama target (elemen sebelum 'Ct') - $target_name = count($target_match) > 1 ? $target_match[count($target_match) - 2] : ''; - } elseif (strpos($rsegmen, 'EndPt|') !== false) { + array_pop($target_parts); + } elseif ($last_part === 'EndPt') { $metric_type = 'EndPt'; - // Mengambil nama target (elemen sebelum 'EndPt') - $target_name = count($target_match) > 1 ? $target_match[count($target_match) - 2] : ''; - } else { - // Jika bukan Ct/EndPt, ini adalah Result murni. - // Target name biasanya adalah elemen terakhir dari array yang tidak kosong. - $target_name = count($target_match) > 0 ? end($target_match) : 'Unknown Target'; + array_pop($target_parts); + } elseif (in_array($last_part, ['Delta Ct', 'LOG'], true)) { + $metric_type = $last_part; + array_pop($target_parts); } + + if (!empty($target_parts) && preg_match('/^\d+$/', (string) end($target_parts))) { + array_pop($target_parts); + } + + $target_name = count($target_parts) > 0 ? end($target_parts) : 'Unknown Target'; $target_name = trim($target_name); @@ -861,11 +913,14 @@ class AstmMessageService } public function processAstmResponse($response, $alat) { // Bersihkan data - $astmData = $this->cleanString($response); + $astmData = $this->normalizeAstmRecordLines($this->cleanString($response)); // Validasi awal: response tidak kosong if (empty($astmData)) { Log::error("ASTM data kosong atau tidak valid."); } + if (stripos($astmData, 'GeneXpert') !== false) { + return $this->processAstmMessagesgenExpert($astmData, $alat); + } $jsonantibiotik = array( 'Oxacillin-OX', 'Cefoxitin-FOX', diff --git a/htdocs/resources/views/admin/report.blade.php b/htdocs/resources/views/admin/report.blade.php index fa8c343a..d45c3374 100644 --- a/htdocs/resources/views/admin/report.blade.php +++ b/htdocs/resources/views/admin/report.blade.php @@ -228,6 +228,7 @@ Hasil MDR Sample Masuk Verifikasi + Tgl. Preliminary Target Duration Keterangan @@ -293,6 +294,7 @@ $(document).ready(function () { { name: 'kd_spesimen', type: 'text'}, { name: 'nm_spesimen', type: 'text'}, { name: 'verifikasi',type: 'text'}, + { name: 'tgl_preliminary',type: 'text'}, { name: 'dlp',type: 'text'}, { name: 'status',type: 'text'}, { name: 'id_bakteri01',type: 'text'}, @@ -354,6 +356,7 @@ $(document).ready(function () { { text: 'Hasil MDR', datafield: 'hasil_mdr', width: 180, cellsalign: 'left', align: 'center', hidden: jenisReport !== 'list_hasil_mdr'}, { text: 'Tgl. Sample', datafield: 'mulai', width: 160, cellsalign: 'left', align: 'center' }, { text: 'Tgl. Hasil', datafield: 'verifikasi', width: 160, cellsalign: 'left', align: 'center' }, + { text: 'Tgl. Preliminary', datafield: 'tgl_preliminary', width: 160, cellsalign: 'left', align: 'center' }, { text: 'Target', datafield: 'modaliti2', width: 100, cellsalign: 'left', align: 'center'}, { text: 'Duration', datafield: 'selisih_hari', width: 100, cellsalign: 'left', align: 'center'}, { text: 'Keterangan', datafield: 'status_target', width: 100, cellsalign: 'left', align: 'center'}, @@ -395,6 +398,7 @@ $(document).ready(function () { ${row.hasil_mdr ?? ''} ${row.mulai ?? ''} ${row.verifikasi ?? ''} + ${row.tgl_preliminary ?? ''} ${row.modaliti2 ?? ''} ${row.selisih_hari ?? ''} ${row.status_target ?? ''}