From 03090cbe7444f1727e39009844649b468b8eab25 Mon Sep 17 00:00:00 2001 From: Dwi Swandhana Date: Sun, 17 May 2026 04:11:19 +0700 Subject: [PATCH] update --- .../app/Http/Controllers/ReportController.php | 64 +++-- htdocs/app/Services/AstmMessageService.php | 224 +++++++++++++----- .../views/dokter/pemeriksaan.blade.php | 108 --------- htdocs/resources/views/dokter/ppds.blade.php | 108 --------- .../views/dokter/ppdsdeveloper.blade.php | 134 ----------- 5 files changed, 213 insertions(+), 425 deletions(-) diff --git a/htdocs/app/Http/Controllers/ReportController.php b/htdocs/app/Http/Controllers/ReportController.php index 904083e4..4d15426b 100644 --- a/htdocs/app/Http/Controllers/ReportController.php +++ b/htdocs/app/Http/Controllers/ReportController.php @@ -1055,6 +1055,53 @@ class ReportController extends Controller return $response; } + private function getZnReportKomponenList() { + return [ + 'id_pewarnaanziehlnielsen', + 'id_pewarnaanziehlnielsensewaktu', + 'lsg_pewarnaanziehlnielsen', + 'lsg_pewarnaanziehlnielsensewaktu', + 'hasilpemeriksaantbbiakan_pagi', + 'hasilpemeriksaantbbiakan_sewaktu', + 'hasilpemeriksaantmikroskopis_hasilpagi', + 'hasilpemeriksaantmikroskopis_hasilsewaktu', + ]; + } + private function normalizeZnReportValue($value) { + $value = trim(strip_tags((string) $value)); + $value = preg_replace('/\s+/', ' ', $value); + $upperValue = strtoupper($value); + + if ($upperValue === 'NEG') { + return 'Tidak ditemukan Bakteri Tahan Asam (BTA)'; + } + + if ($upperValue === '1-9') { + return 'Ditemukan Bakteri Tahan Asam 0-9 BTA (scanty)'; + } + + if ($value === '+') { + return 'Ditemukan Bakteri Tahan Asam (BTA) 1+'; + } + + if ($value === '++') { + return 'Ditemukan Bakteri Tahan Asam (BTA) 2+'; + } + + if ($value === '+++') { + return 'Ditemukan Bakteri Tahan Asam (BTA) 3+'; + } + + return $value; + } + private function periksaHasZnReportValue($periksa, $nilai, $komponenList) { + return $periksa->komponen + ->whereIn('komponen', $komponenList) + ->filter(function ($komponen) use ($nilai) { + return $this->normalizeZnReportValue($komponen->isidata) === $nilai; + }) + ->count() > 0; + } public function genZNreport(Request $request) { $data = []; $bulan = $request->input('bulan'); @@ -1068,12 +1115,7 @@ class ReportController extends Controller } // komponen Ziehl yang mau dianalisa - $komponenList = [ - 'id_pewarnaanziehlnielsen', - 'id_pewarnaanziehlnielsensewaktu', - 'lsg_pewarnaanziehlnielsen', - 'lsg_pewarnaanziehlnielsensewaktu' - ]; + $komponenList = $this->getZnReportKomponenList(); // Nilai Ziehl yang ingin dihitung $nilaiList = Organisms::where('kelompok', 'Pewarnaan Ziehl Nielsen')->pluck('name')->toArray(); @@ -1111,10 +1153,7 @@ class ReportController extends Controller ->where('kd_spesimen', $spesimen) ->where('jkpasien', 'L') ->filter(function($px) use ($nilai, $komponenList){ - return $px->komponen - ->whereIn('komponen', $komponenList) - ->where('isidata', $nilai) - ->count() > 0; + return $this->periksaHasZnReportValue($px, $nilai, $komponenList); })->count(); // hitung perempuan @@ -1122,10 +1161,7 @@ class ReportController extends Controller ->where('kd_spesimen', $spesimen) ->where('jkpasien', 'P') ->filter(function($px) use ($nilai, $komponenList){ - return $px->komponen - ->whereIn('komponen', $komponenList) - ->where('isidata', $nilai) - ->count() > 0; + return $this->periksaHasZnReportValue($px, $nilai, $komponenList); })->count(); } } diff --git a/htdocs/app/Services/AstmMessageService.php b/htdocs/app/Services/AstmMessageService.php index df1b2beb..f3267975 100644 --- a/htdocs/app/Services/AstmMessageService.php +++ b/htdocs/app/Services/AstmMessageService.php @@ -600,55 +600,64 @@ class AstmMessageService return false; } } + public function processAstmMessagesgenExpert($response, $alat) { - // 1. Normalisasi karakter pembatas baris (\r\n, \r, atau \n diubah jadi \n) - $normalizedData = str_replace(["\r\n", "\r"], "\n", $response); - $segments = explode("\n", $normalizedData); + $normalizedData = str_replace(["\r\n", "\r"], "\n", $response); + $segments = explode("\n", $normalizedData); + $patient_id = ''; + $patient_name = ''; + $accession_number = ''; + + // Array untuk menyimpan data terstruktur + $parsedResults = []; + $hasil_list = []; // Tetap dipertahankan untuk kebutuhan legacy/summary - $patient_id = ''; - $patient_name = ''; - $accession_number = ''; // NoReg - $hasil_list = []; - - // 2. Looping setiap baris data ASTM foreach ($segments as $rsegmen) { $cekdata = explode('|', $rsegmen); if (empty($cekdata[0])) continue; - + $recordType = preg_replace("/[^a-zA-Z]/", "", $cekdata[0]); - - // Ekstrak Data Pasien (P) + if ($recordType === 'P') { $patient_id = $cekdata[3] ?? ($cekdata[4] ?? ''); if (isset($cekdata[5])) { $patient_name = trim(str_replace('^', ' ', $cekdata[5])); } } - - // Ekstrak Nomor Order (O) + if ($recordType === 'O') { $accession_number = $cekdata[2] ?? ''; } - - // Ekstrak Hasil Analisa (R) + if ($recordType === 'R') { if (isset($cekdata[2]) && isset($cekdata[3])) { - $test_info = $cekdata[2]; // Format contoh: ^^^MTB-RIF_ULTRA 2^^^MTB^ - $result_val = trim(str_replace('^', '', $cekdata[3])); // Contoh: DETECTED / PASS / INVALID - - // [KUNCI]: Buang baris yang berisi kurva angka (Ct / EndPt) agar tidak nyampah dan kepanjangan - if (strpos($rsegmen, 'Ct|') === false && strpos($rsegmen, 'EndPt|') === false && $result_val !== '') { + $test_info_raw = $cekdata[2]; + $result_val = trim(str_replace('^', '', $cekdata[3])); + + if ($result_val !== '') { + // Pecah test info berdasarkan '^' + $test_info = explode('^', $test_info_raw); - // Ambil nama target spesifik (misal 'MTB' atau 'RIF Resistance' atau 'SPC') - $target_match = explode('^^^', $test_info); - $target_name = ''; - if (count($target_match) > 1) { - $target_name = trim(str_replace('^', '', end($target_match))); + // Pada format GeneXpert: index ke-6 biasanya nama target (FII, FII 20210G, dll) + // index ke-7 biasanya penanda tipe data (Ct, EndPt) + $target_name = $test_info[6] ?? 'Unknown Target'; + $metric_type = $test_info[7] ?? 'Result'; // Jika tidak ada, berarti ini Result (POS/NEG) + + // Inisialisasi array untuk target ini jika belum ada + if (!isset($parsedResults[$target_name])) { + $parsedResults[$target_name] = [ + 'Result' => '-', + 'Ct' => '-', + 'EndPt' => '-' + ]; } - // Simpan ke array jika valid - if ($target_name && $result_val) { + // Masukkan nilai ke dalam struktur data + $parsedResults[$target_name][$metric_type] = $result_val; + + // Untuk summary legacy (kolom organism/additional_result) + if ($metric_type === 'Result') { $hasil_list[] = $target_name . ": " . $result_val; } } @@ -661,50 +670,143 @@ class AstmMessageService return false; } - // 3. Gabungkan hasil dari array menjadi 1 string ("MTB: DETECTED | RIF Resistance: NOT DETECTED") - $kesimpulan = implode(" | ", $hasil_list); + // ==================================================================== + // MEMBUAT HTML REPORT & GRAFIK (CHART.JS) + // ==================================================================== + + // 1. Buat Tabel HTML + $reporthtml = '
'; + $reporthtml .= '

GeneXpert Assay Result

'; + $reporthtml .= ''; + $reporthtml .= ' + + + + + '; - // [PENTING] Potong text agar TIDAK ERROR di Postgres (Varchar 100) - $kesimpulan_safe = substr($kesimpulan, 0, 100); + $chartLabels = []; + $chartCtData = []; + $chartEndPtData = []; + + foreach ($parsedResults as $target => $data) { + $reporthtml .= " + + + + + "; + + // Siapkan data untuk grafik (hanya ambil target yang memiliki nilai numerik Ct/EndPt) + if (is_numeric($data['Ct']) || is_numeric($data['EndPt'])) { + $chartLabels[] = $target; + $chartCtData[] = is_numeric($data['Ct']) ? (float)$data['Ct'] : 0; + $chartEndPtData[] = is_numeric($data['EndPt']) ? (float)$data['EndPt'] : 0; + } + } + $reporthtml .= '
Target/AnalyteResultCt ValueEndPt
{$target}{$data['Result']}{$data['Ct']}{$data['EndPt']}
'; + + // 2. Buat Grafik menggunakan Chart.js (Inject Script) + if (!empty($chartLabels)) { + $chartId = 'gxChart_' . preg_replace('/[^a-zA-Z0-9]/', '', $accession_number); + $labelsJson = json_encode($chartLabels); + $ctJson = json_encode($chartCtData); + $endPtJson = json_encode($chartEndPtData); + + // Tambahkan Canvas untuk grafik + $reporthtml .= '
'; + $reporthtml .= ''; + $reporthtml .= '
'; + + // Tambahkan script Chart.js (asumsi CDN) dan inisialisasi + $reporthtml .= " + + + "; + } + $reporthtml .= '
'; + + // ==================================================================== + // SIMPAN KE DATABASE + // ==================================================================== + + $kesimpulan = implode(" | ", $hasil_list); + $kesimpulan_safe = substr($kesimpulan, 0, 100); try { - // Update status tabel Periksa Periksa::where('nofoto', $accession_number) ->whereNotIn('status', ['Selesai', 'Arsip', 'Dibatalkan (Arsip)', 'Batal']) ->update([ 'status' => 'Data GeneXpert di Terima' ]); - // Update atau Insert ke Komponen Jawaban - if (!empty($kesimpulan)) { - KomponenJawaban::updateOrCreate( - [ - 'accnumber' => $accession_number, - 'komponen' => 'genexpert_result', // Ganti key ini sesuai dengan penamaan di frontend Anda - ], - [ - 'isidata' => substr($kesimpulan, 0, 500), // Di tabel ini biasanya lebih panjang - 'template' => 'GeneXpert', - 'created_by' => 'GeneXpert Middleware' - ] - ); - } - - // Opsional: Simpan log sejarah hasil di ResultSample seperti alat Vitek/BD - $resultSample = ResultSample::firstOrNew(['accession_number' => $accession_number]); - $resultSample->sender_name = $alat; - $resultSample->patient_id = substr($patient_id, 0, 50); - $resultSample->patient_name_first = substr($patient_name, 0, 100); - $resultSample->organism = $kesimpulan_safe; // Limit varchar(100) ditaati di sini - $resultSample->additional_result = json_encode($hasil_list); - $resultSample->message_datetime = date('Y-m-d H:i:s'); - $resultSample->save(); - - Log::info("GeneXpert Result Disimpan", ["NoReg" => $accession_number, "Hasil" => $kesimpulan_safe]); - // Kembalikan TRUE agar update 'processed' => 1 di method processAstmMessagesLokal Anda tereksekusi + Riwayat::create([ + 'nofoto' => $accession_number, + 'jawaban' => $reporthtml, + 'inputor' => $alat, + 'keterangan' => date('Y-m-d H:i:s'), + 'verifikasi' => '', + ]); + + $resultSample = ResultSample::firstOrNew(['accession_number' => $accession_number]); + $resultSample->sender_name = $alat; + $resultSample->patient_id = substr($patient_id, 0, 50); + $resultSample->patient_name_first = substr($patient_name, 0, 100); + $resultSample->organism = $kesimpulan_safe; // Tetap menyimpan text summary + $resultSample->additional_result = json_encode($parsedResults); // Menyimpan JSON utuh agar lebih informatif + $resultSample->message_datetime = date('Y-m-d H:i:s'); + $resultSample->save(); + Log::info("GeneXpert Result Disimpan", ["NoReg" => $accession_number, "Hasil" => $kesimpulan_safe]); return true; - } catch (\Exception $e) { Log::error("GeneXpert DB Save Error: " . $e->getMessage()); return false; diff --git a/htdocs/resources/views/dokter/pemeriksaan.blade.php b/htdocs/resources/views/dokter/pemeriksaan.blade.php index 2c9f406f..1b307576 100644 --- a/htdocs/resources/views/dokter/pemeriksaan.blade.php +++ b/htdocs/resources/views/dokter/pemeriksaan.blade.php @@ -2094,9 +2094,6 @@