This commit is contained in:
Dwi Swandhana
2026-05-17 04:11:19 +07:00
parent 45b4f41e57
commit 03090cbe74
5 changed files with 213 additions and 425 deletions
+163 -61
View File
@@ -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 = '<div class="genexpert-report" style="font-family: Arial, sans-serif;">';
$reporthtml .= '<h4 style="margin-bottom:10px;">GeneXpert Assay Result</h4>';
$reporthtml .= '<table border="1" cellpadding="5" style="width: 100%; border-collapse: collapse; text-align: left; margin-bottom: 20px;">';
$reporthtml .= '<tr style="background-color: #f4f4f4;">
<th>Target/Analyte</th>
<th>Result</th>
<th>Ct Value</th>
<th>EndPt</th>
</tr>';
// [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 .= "<tr>
<td><strong>{$target}</strong></td>
<td>{$data['Result']}</td>
<td>{$data['Ct']}</td>
<td>{$data['EndPt']}</td>
</tr>";
// 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 .= '</table>';
// 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 .= '<div style="width: 100%; max-width: 800px; margin: auto;">';
$reporthtml .= '<canvas id="'.$chartId.'"></canvas>';
$reporthtml .= '</div>';
// Tambahkan script Chart.js (asumsi CDN) dan inisialisasi
$reporthtml .= "
<script src=\"https://cdn.jsdelivr.net/npm/chart.js\"></script>
<script>
// Gunakan DOMContentLoaded agar script jalan setelah HTML di-render di frontend
document.addEventListener('DOMContentLoaded', function() {
var ctx = document.getElementById('{$chartId}').getContext('2d');
new Chart(ctx, {
type: 'bar', // Menggunakan kombinasi Bar & Line chart
data: {
labels: {$labelsJson},
datasets: [
{
label: 'Ct Value',
data: {$ctJson},
backgroundColor: 'rgba(54, 162, 235, 0.6)',
borderColor: 'rgba(54, 162, 235, 1)',
borderWidth: 1,
yAxisID: 'y'
},
{
label: 'End Point',
data: {$endPtJson},
type: 'line',
borderColor: 'rgba(255, 99, 132, 1)',
backgroundColor: 'rgba(255, 99, 132, 0.2)',
borderWidth: 2,
yAxisID: 'y1'
}
]
},
options: {
responsive: true,
scales: {
y: {
type: 'linear',
display: true,
position: 'left',
title: { display: true, text: 'Ct Value' }
},
y1: {
type: 'linear',
display: true,
position: 'right',
title: { display: true, text: 'EndPt' },
grid: { drawOnChartArea: false } // Agar garis grid tidak bertumpuk
}
}
}
});
});
</script>
";
}
$reporthtml .= '</div>';
// ====================================================================
// 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;