Files
lis/htdocs/app/Http/Controllers/MobileApiController.php
T
2026-07-22 09:07:43 +07:00

1150 lines
54 KiB
PHP

<?php
namespace App\Http\Controllers;
use App\KomponenJawaban;
use App\CriticalValueSample;
use App\Organisms;
use App\Periksa;
use App\PeriksaSYNC;
use App\Riwayat;
use App\Subjawaban;
use App\User;
use Carbon\Carbon;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Crypt;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Facades\Session;
class MobileApiController extends Controller
{
protected array $bookLabels = [
'buku01' => 'Cairan Steril',
'buku02' => 'CCI',
'buku03' => 'Darah',
'buku04' => 'HIV',
'buku05' => 'Kuku, Kulit, Adnexa',
'buku06' => 'Kultur TB',
'buku07' => 'Pus dan Jaringan',
'buku08' => 'Sputum',
'buku09' => 'Swab',
'buku10' => 'TCM TB',
'buku11' => 'TCM non-TB',
'buku12' => 'Urine',
'buku13' => 'Feces',
'buku0' => 'Lainnya',
];
protected function bookPoliMap(): array
{
return [
'buku01' => [15,16,43,47,48,66,96,205,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223],
'buku02' => [20],
'buku03' => [7,8,13,17,29,33,44,107,114,115,199,200,201,202],
'buku04' => [30],
'buku05' => [165,179,180,181,183,184,185,187,188,189,190,192,194,195,196,198],
'buku06' => [26,40,45,52,53,56,60,61,68,69,75,92,102,122,123,136,137,144,145,152,153,233],
'buku07' => [18,19,32,35,46,49,50,54,57,58,59,72,160,182,186,191,193,197,206,207,208,224,225,226,227,228,234,235,236,237],
'buku08' => [1,12,23,24,36,39,229,230,231,232],
'buku09' => [2,4,5,9,10,11,21,22,27,34,41,42,51,63,64,65,85,86,87,88,93,97,118,67,121,125,126,127,128,129,130,132,133,134,135,140,147,158,159,161,162,163,164,166,167,168,169,170,171,172,173,174,175,176,177,178],
'buku10' => [14,28,55,62,94,104,105,124,138,146],
'buku11' => [79,80,81,82,83,84,203],
'buku12' => [3,6,25,31,154,155,156,157],
'buku13' => [37,38,148,149,204],
];
}
protected function activeExaminationQuery()
{
return Periksa::query()
->where(function ($query) {
$query->where(function ($sub) {
$sub->whereNotIn('status', ['Selesai', 'Arsip'])
->where('status', 'not like', 'Dibatalkan%');
})->orWhereNull('status');
});
}
protected function userFromRequest(Request $request): ?User
{
$header = (string) $request->bearerToken();
if ($header === '') {
return null;
}
try {
$payload = Crypt::decryptString($header);
$data = json_decode($payload, true);
$user = User::find($data['id'] ?? null);
if (!$user || ($data['password'] ?? '') !== $user->password) {
return null;
}
return $user;
} catch (\Throwable $e) {
return null;
}
}
protected function requireUser(Request $request): User
{
$user = $this->userFromRequest($request);
abort_if(!$user, 401, 'Token login tidak valid.');
return $user;
}
protected function tokenFor(User $user): string
{
return Crypt::encryptString(json_encode([
'id' => $user->id,
'password' => $user->password,
'issued_at' => now()->toDateTimeString(),
]));
}
protected function resolveTargetDays($modaliti2): int
{
return (!empty($modaliti2) && is_numeric($modaliti2) && intval($modaliti2) > 0)
? intval($modaliti2)
: 1;
}
protected function resolveMasterFromPoliId($poliId): string
{
foreach ($this->bookPoliMap() as $master => $poliIds) {
if (in_array((int) $poliId, $poliIds, true)) {
return $master;
}
}
return 'buku0';
}
protected function examinationPayload(Periksa $row): array
{
$formatDate = function ($value): ?string {
if (!$value) {
return null;
}
try {
return Carbon::parse($value)->format('Y-m-d H:i:s');
} catch (\Throwable $e) {
return (string) $value;
}
};
return [
'id' => $row->id,
'master' => $this->resolveMasterFromPoliId($row->poli_id),
'master_label' => $this->bookLabels[$this->resolveMasterFromPoliId($row->poli_id)] ?? 'Lainnya',
'nofoto' => $row->nofoto,
'noregister' => $row->noregister,
'nmpasien' => $row->nmpasien,
'jkpasien' => $row->jkpasien,
'usia' => $row->usia,
'tgllahirpasien' => $row->tgllahirpasien,
'tlppasien' => $row->tlppasien,
'alamatpasien' => $row->alamatpasien,
'reques' => $row->reques,
'asalpasien' => $row->asalpasien,
'ruangan' => $row->ruangan,
'analis' => $row->analis,
'ppds3' => $row->ppdssenior,
'dokter_id' => $row->dokter_id,
'klinisi' => $row->klinisi,
'klinis' => $row->klinis,
'nmdokter' => $row->nmdokter,
'nm_spesimen' => $row->nm_spesimen,
'kesimpulan' => $row->kesimpulan,
'dlp' => $row->dlp,
'tanggalregis' => $row->tanggalregis,
'tanggalsampel' => $row->tanggalsampel,
'pengambilan' => $row->pengambilan,
'asalpengirim' => $row->asalpengirim,
'status' => $row->status ?: 'NEW',
'daftar' => $formatDate($row->daftar),
'verifikasi' => $formatDate($row->verifikasi),
];
}
public function login(Request $request)
{
$request->validate([
'username' => ['required'],
'password' => ['required'],
]);
$user = User::where('username', $request->input('username'))->first();
if (!$user || !Hash::check((string) $request->input('password'), $user->password)) {
return response()->json(['message' => 'Username atau password salah.'], 401);
}
$photo = $user->getPhoto->xfile ?? '/doctor.png';
$user->active_status = 1;
$user->save();
return response()->json([
'token' => $this->tokenFor($user),
'user' => [
'id' => $user->id,
'nama' => $user->nama,
'username' => $user->username,
'previlage' => $user->previlage,
'photo' => url($photo),
],
]);
}
public function ping()
{
return response()->json([
'status' => 'ok',
'application' => config('global.namaapps', config('app.name')),
'time' => now()->toDateTimeString(),
]);
}
public function dashboard(Request $request)
{
$user = $this->requireUser($request);
$allData = $this->activeExaminationQuery()->get();
$mapped = collect($this->bookPoliMap())->flatten()->all();
$books = [];
foreach ($this->bookLabels as $master => $label) {
$count = $master === 'buku0'
? $allData->filter(fn ($item) => !in_array($item->poli_id, $mapped))->count()
: $allData->whereIn('poli_id', $this->bookPoliMap()[$master] ?? [])->count();
$books[] = ['master' => $master, 'label' => $label, 'total' => $count];
}
return response()->json([
'user' => [
'id' => $user->id,
'nama' => $user->nama,
'username' => $user->username,
'previlage' => $user->previlage,
],
'summary' => [
'total_ppds' => User::where('previlage', 'ppds')->count(),
'butuh_verifikasi' => Periksa::where('status', 'like', '%Un Verified%')->count(),
'antrian_hari_ini' => Periksa::whereDate('daftar', Carbon::today())->count(),
'antrian_sinkron' => PeriksaSYNC::where('created_by', $user->username)->where('status', '')->count(),
],
'books' => $books,
'early_warning_groups' => $this->earlyWarningGroups(),
]);
}
public function examinations(Request $request, string $master)
{
$this->requireUser($request);
$query = $this->activeExaminationQuery();
$mapped = collect($this->bookPoliMap())->flatten()->all();
if ($master === 'buku0') {
$query->whereNotIn('poli_id', $mapped);
} elseif (isset($this->bookPoliMap()[$master])) {
$query->whereIn('poli_id', $this->bookPoliMap()[$master]);
} else {
return response()->json(['message' => 'Kategori pemeriksaan tidak dikenal.'], 404);
}
$search = trim((string) $request->query('search', ''));
if ($search !== '') {
$query->where(function ($q) use ($search) {
$q->where('nofoto', 'like', "%{$search}%")
->orWhere('noregister', 'like', "%{$search}%")
->orWhere('nmpasien', 'like', "%{$search}%")
->orWhere('reques', 'like', "%{$search}%");
});
}
$items = $query->orderBy('daftar', 'ASC')->limit(250)->get()->map(fn ($row) => $this->examinationPayload($row));
return response()->json([
'master' => $master,
'label' => $this->bookLabels[$master],
'items' => $items,
]);
}
public function examination(Request $request, int $id)
{
$this->requireUser($request);
$row = Periksa::find($id);
abort_if(!$row, 404, 'Data pemeriksaan tidak ditemukan.');
return response()->json([
'item' => $this->examinationPayload($row),
'expertise_url' => url('mobile/expertise/'.$row->id).'?token='.rawurlencode((string) $request->bearerToken()),
'result_url' => $row->nofoto ? url('hasil/'.$row->nofoto) : null,
]);
}
public function expertise(Request $request, int $id)
{
$user = $this->requireUser($request);
$row = Periksa::find($id);
abort_if(!$row, 404, 'Data pemeriksaan tidak ditemukan.');
$dlp = trim((string) ($row->dlp ?? ''));
return response()->json([
'item' => $this->examinationPayload($row),
'user' => [
'id' => $user->id,
'nama' => $user->nama,
'previlage' => $user->previlage,
],
'dlp' => $dlp,
'templates' => $this->templateList(),
'staff_options' => $this->staffOptions(),
'option_sets' => $this->expertiseOptionSets(),
'is_critical' => CriticalValueSample::where('periksa_id', $row->id)->exists(),
'components' => $dlp === '' ? (object) [] : $this->componentMap($row->nofoto, $dlp),
'fields' => $dlp === '' ? [] : $this->expertiseFields($dlp),
]);
}
public function setExpertiseTemplate(Request $request, int $id)
{
$user = $this->requireUser($request);
$request->validate(['dlp' => ['required', 'string']]);
$row = Periksa::find($id);
abort_if(!$row, 404, 'Data pemeriksaan tidak ditemukan.');
$dlp = trim((string) $request->input('dlp'));
$row->update([
'dlp' => $dlp,
'nmdrafter' => $user->nama,
'nmexcutor' => $user->nama,
'excutor' => $user->id,
'status' => $row->status ?: 'Pemeriksaan awal',
]);
return response()->json([
'message' => 'Template expertise dipilih.',
'item' => $this->examinationPayload($row->fresh()),
'dlp' => $dlp,
'components' => $this->componentMap($row->nofoto, $dlp),
'fields' => $this->expertiseFields($dlp),
]);
}
public function saveExpertise(Request $request, int $id)
{
$user = $this->requireUser($request);
$request->validate([
'dlp' => ['required', 'string'],
'action' => ['nullable', 'string'],
'fields' => ['nullable', 'array'],
'keterangan' => ['nullable', 'string'],
'analis' => ['nullable'],
'ppds3' => ['nullable'],
'dokter' => ['nullable'],
'nilai_kritis' => ['nullable'],
]);
$row = Periksa::find($id);
abort_if(!$row, 404, 'Data pemeriksaan tidak ditemukan.');
$dlp = trim((string) $request->input('dlp'));
$fields = $request->input('fields', []);
$keterangan = (string) $request->input('keterangan', '');
$action = (string) $request->input('action', 'Draft');
$analis = $request->input('analis');
$ppds3 = $request->input('ppds3');
$dokter = $request->input('dokter');
$atlmUser = User::find($analis);
$ppdsUser = User::find($ppds3);
$spvUser = User::find($dokter);
foreach ($fields as $key => $value) {
if ($value === '' || $value === null || $value === 'Pilih Salah Satu') {
KomponenJawaban::where('accnumber', $row->nofoto)
->where('template', $dlp)
->where('komponen', $key)
->delete();
continue;
}
KomponenJawaban::updateOrCreate(
[
'accnumber' => $row->nofoto,
'komponen' => $key,
],
[
'isidata' => is_array($value) ? json_encode($value) : $value,
'template' => $dlp,
'created_by' => $user->nama,
]
);
}
$status = match ($action) {
'verifikasi' => 'Selesai',
'preliminary' => 'Preliminary Results',
'Permohonan Verifikasi' => 'Expertise Saved (Un Verified)',
'Permohonan Verifikasi Preliminary' => 'Otor Maldi (Un Verified)',
'statuspewarnaanlsg' => $this->resolvePeriksaHierarchyStatus($row->status, 'Pewarnaan Langsung'),
default => 'Pemeriksaan awal',
};
$updateData = [
'keterangan' => $keterangan,
'dlp' => $dlp,
'analis' => $analis,
'nmanalis' => $atlmUser->nama ?? null,
'dokter_id' => $action === 'verifikasi' || $action === 'preliminary' ? $user->id : $dokter,
'nmdokter' => $action === 'verifikasi' || $action === 'preliminary' ? $user->nama : ($spvUser->nama ?? null),
'ppdssenior' => $ppds3,
'nmppdssenior' => $ppdsUser->nama ?? null,
'nmdrafter' => $user->nama,
'nmexcutor' => $user->nama,
'excutor' => $user->id,
'baca' => in_array($action, ['Permohonan Verifikasi', 'Permohonan Verifikasi Preliminary'], true) ? now() : $row->baca,
'nmpembaca' => in_array($action, ['Permohonan Verifikasi', 'Permohonan Verifikasi Preliminary'], true) ? $user->nama : $row->nmpembaca,
'status' => $status,
];
if (in_array($action, ['verifikasi', 'preliminary'], true)) {
$updateData['verifikasi'] = now();
$updateData['akhir'] = $action === 'verifikasi' ? now() : $row->akhir;
}
$row->update($updateData);
if ($this->shouldMarkAsCritical($request)) {
$this->upsertCriticalValueSample($row->fresh(), $user);
}
Riwayat::create([
'nofoto' => $row->nofoto,
'jawaban' => $keterangan !== '' ? $keterangan : json_encode($fields),
'inputor' => $user->nama,
'keterangan' => match ($action) {
'verifikasi' => 'Expertise',
'preliminary' => 'Preliminary Results',
'Permohonan Verifikasi' => 'Kirim ke SPV',
'Permohonan Verifikasi Preliminary' => 'Kirim Preliminary ke SPV',
'statuspewarnaanlsg' => 'Pewarnaan Langsung',
default => 'Draft',
},
'verifikasi' => in_array($action, ['verifikasi', 'preliminary'], true) ? 'Accepted' : '',
]);
return response()->json([
'message' => match ($action) {
'verifikasi' => 'Expertise Saved',
'preliminary' => 'Preliminary Results Saved',
'Permohonan Verifikasi' => 'Permohonan Verifikasi Terkirim',
'Permohonan Verifikasi Preliminary' => 'Permohonan Verifikasi Preliminary Terkirim',
'statuspewarnaanlsg' => 'Pewarnaan Langsung tersimpan',
default => 'Draft Expertise Saved',
},
'item' => $this->examinationPayload($row->fresh()),
'components' => $this->componentMap($row->nofoto, $dlp),
]);
}
protected function templateList(): array
{
return Subjawaban::orderBy('kategori')
->orderBy('judul')
->get(['id', 'kategori', 'judul', 'subjawaban', 'kesimpulan'])
->map(fn ($row) => [
'id' => $row->id,
'kategori' => (string) $row->kategori,
'judul' => (string) $row->judul,
'isine' => trim((string) $row->subjawaban.' '.(string) $row->kesimpulan),
])
->values()
->toArray();
}
protected function componentMap($nofoto, string $dlp): array
{
return KomponenJawaban::where('accnumber', $nofoto)
->where('template', $dlp)
->get(['komponen', 'isidata'])
->mapWithKeys(fn ($row) => [$row->komponen => $this->decodeComponentValue($row->isidata)])
->toArray();
}
protected function decodeComponentValue($value)
{
if (!is_string($value)) {
return $value;
}
$decoded = json_decode($value, true);
return json_last_error() === JSON_ERROR_NONE ? $decoded : $value;
}
protected function staffOptions(): array
{
$mapUser = fn ($row) => [
'id' => $row->id,
'nama' => $row->nama,
'username' => $row->username,
'previlage' => $row->previlage,
];
return [
'analis' => User::where('previlage', 'analis')->orderBy('nama')->get()->map($mapUser)->values()->toArray(),
'ppds' => User::where('previlage', 'ppds')->orderBy('nama')->get()->map($mapUser)->values()->toArray(),
'dokters' => User::where('previlage', 'supervisor')->orderBy('nama')->get()->map($mapUser)->values()->toArray(),
];
}
protected function expertiseOptionSets(): array
{
$organismNames = fn ($kelompok) => Organisms::where('kelompok', $kelompok)
->orderBy('category')
->orderBy('name')
->pluck('name')
->filter()
->values()
->toArray();
return [
'jsonsputum' => $organismNames('Sputum'),
'jsonswabtenggorok' => $organismNames('Swab Tenggorok'),
'jsonurine' => $organismNames('Urine'),
'jsonswabperineum' => $organismNames('Swab perineum'),
'jsonselepitel' => $organismNames('Sel Epitel'),
'jsonselradang' => $organismNames('Sel Radang'),
'jsonmikroorganisme' => $organismNames('Mikroorganisme'),
'jsonmikroorganismeoptional' => Organisms::orderBy('category')
->orderBy('name')
->pluck('name')
->filter()
->values()
->toArray(),
'jsonjumlahlactobacillus' => $organismNames('Jumlah Lactobacillus'),
'jsonjumlahgardnerella' => $organismNames('Jumlah Gardnerella'),
'jsonjumlahmobiluncus' => $organismNames('Jumlah Mobiluncus'),
'jsonpewarnaanziehlnielsen' => $organismNames('Pewarnaan Ziehl Neelsen'),
'jsonpewarnaankoh' => $organismNames('Pewarnaan KOH'),
'jsonpewarnaanneisser' => $organismNames('Pewarnaan Neisser'),
'jsonpewarnaannegatif' => $organismNames('Pewarnaan Negatif'),
'jsonpewarnaanspora' => $organismNames('Pewarnaan Spora'),
'jsonpewarnaangiemsa' => $organismNames('Pewarnaan Giemsa'),
'jsonbiakankultur' => $organismNames('Biakan Kultur'),
'jsonvlparameter' => $organismNames('Viral Load Parameter'),
];
}
protected function shouldMarkAsCritical(Request $request): bool
{
$flag = strtolower((string) $request->input('nilai_kritis', '0'));
return in_array($flag, ['1', 'true', 'yes', 'on'], true);
}
protected function upsertCriticalValueSample(Periksa $periksa, User $user): void
{
$criticalSample = CriticalValueSample::firstOrNew(['periksa_id' => $periksa->id]);
$criticalSample->fill([
'nofoto' => $periksa->nofoto,
'noregister' => $periksa->noregister,
'nmpasien' => $periksa->nmpasien,
'nm_spesimen' => $periksa->nm_spesimen,
'asalpasien' => $periksa->asalpasien,
'critical_set_at' => now(),
'critical_set_by_user_id' => $user->id,
'critical_set_by_name' => $user->nama,
]);
$criticalSample->save();
}
protected function expertiseFields(string $dlp): array
{
$select = fn ($name, $label, $options) => ['name' => $name, 'label' => $label, 'type' => 'select', 'options' => $options];
$text = fn ($name, $label) => ['name' => $name, 'label' => $label, 'type' => 'text'];
$area = fn ($name, $label) => ['name' => $name, 'label' => $label, 'type' => 'textarea'];
$multi = fn ($name, $label, $options) => ['name' => $name, 'label' => $label, 'type' => 'multiselect', 'options' => $options];
$yn = ['Positif', 'Negatif'];
$tbResult = ['+++', '++', '+', '1-9', 'Neg'];
$organismOptions = ['Tidak ditemukan', 'Sedikit', 'Sedang', 'Banyak', 'lainnya'];
$sirOptions = ['ESBL', 'MRSA', 'MDR', 'XDR', 'PDR', 'Carbapenem Resistant', 'MDR Carbapenem Resistant', 'XDR Carbapenem Resistant'];
$colonyOptions = ['>= 10^5 CFU/ml Urine (Bakteriuria bermakna)', '>= 10^5 CFU/ml Urine (Candiduria bermakna)', '>= 10^3 CFU/ml Urine (Bakteriuria bermakna)', '8 x 10^3 CFU/ml Urine (Bakteriuria bermakna)', 'lainnya'];
$printOptions = ['YA', 'TIDAK'];
return match ($dlp) {
'CCI' => [
$select('id_sputum', 'Sputum', $organismOptions),
$select('id_swabtenggorok', 'Swab Tenggorok', $organismOptions),
$select('id_urine', 'Urine', $organismOptions),
$select('id_swabperineum', 'Swab Perineum', $organismOptions),
$text('bakteri', 'Vitek - Bakteri'),
$select('bakterisir', 'Vitek - SIR', $sirOptions),
$select('id_bakterihitungkol', 'Vitek - Hitung Koloni', $colonyOptions),
$text('id_bakterihitungkolteks', 'Vitek - Hitung Koloni Lainnya'),
$select('id_baktericetak', 'Vitek - Cetak', $printOptions),
$text('id_bakteri01', 'MALDITOF - Bakteri'),
$text('id_antibiotikmanual1', 'MALDITOF - Set Antibiotik'),
$select('id_bakterisir01', 'MALDITOF - SIR', $sirOptions),
$select('id_bakterihitungkol01', 'MALDITOF - Hitung Koloni', $colonyOptions),
$text('id_bakterihitungkolteks01', 'MALDITOF - Hitung Koloni Lainnya'),
$select('id_bakteri01cetak', 'MALDITOF - Cetak', $printOptions),
$text('id_bakteri02', 'Bakteri Manual I - Bakteri'),
$text('id_antibiotikmanual2', 'Bakteri Manual I - Set Antibiotik'),
$select('id_bakterisir02', 'Bakteri Manual I - SIR', $sirOptions),
$select('id_bakterihitungkol02', 'Bakteri Manual I - Hitung Koloni', $colonyOptions),
$text('id_bakterihitungkolteks02', 'Bakteri Manual I - Hitung Koloni Lainnya'),
$select('id_bakteri02cetak', 'Bakteri Manual I - Cetak', $printOptions),
$area('keterangan', 'Keterangan Expertise'),
],
'Kultur' => [
$select('id_selepitel', 'Sel Epitel', $organismOptions),
$select('id_selradang', 'Sel Radang', $organismOptions),
$select('id_mikroorganisme', 'Mikroorganisme', $organismOptions),
$multi('id_mikroorganismeoptional', 'Mikroorganisme Tambahan', ['Gram positif', 'Gram negatif', 'Yeast cell', 'Basil', 'Kokus']),
$select('id_jumlahlactobacillus', 'Lactobacillus - Jumlah Per Lapang', $organismOptions),
$select('id_lactobacillus', 'Lactobacillus - Skor', ['0', '1', '2', '3', '4']),
$select('id_jumlahgardnerella', 'Gardnerella - Jumlah Per Lapang', $organismOptions),
$select('id_gardnerella', 'Gardnerella - Skor', ['0', '1', '2', '3', '4']),
$select('id_jumlahmobiluncus', 'Mobiluncus - Jumlah Per Lapang', $organismOptions),
$select('id_mobiluncus', 'Mobiluncus - Skor', ['0', '1', '2', '3', '4']),
$select('id_pewarnaanziehlnielsen', 'Pewarnaan Ziehl Neelsen Pagi', $organismOptions),
$select('id_pewarnaanziehlnielsensewaktu', 'Pewarnaan Ziehl Neelsen Sewaktu', $organismOptions),
$select('id_pewarnaangiesma', 'Pewarnaan Giemsa', ['Tidak ditemukan', 'Ditemukan', 'lainnya']),
$text('id_pewarnaangiesmaoptional', 'Pewarnaan Giemsa Lainnya'),
$select('id_pewarnaankoh', 'Pewarnaan KOH', ['Tidak ditemukan', 'Ditemukan', 'lainnya']),
$text('id_pewarnaankohoptional', 'Pewarnaan KOH Lainnya'),
$select('id_pewarnaanneisser', 'Pewarnaan Neisser', $organismOptions),
$select('id_pewarnaannegatif', 'Pewarnaan Negatif', $organismOptions),
$select('id_pewarnaanspora', 'Pewarnaan Spora', $organismOptions),
$text('bd_result', 'BD Result'),
$text('bd_result_date', 'BD Result Date'),
$select('id_kbamc', 'Kirby Bauer AMC', array_merge(['Tidak dilakukan'], range(1, 42))),
$select('id_sirkbamc', 'Kirby Bauer AMC SIR', ['S', 'I', 'R']),
$select('id_kbak', 'Kirby Bauer AK', array_merge(['Tidak dilakukan'], range(1, 42))),
$select('id_sirkbak', 'Kirby Bauer AK SIR', ['S', 'I', 'R']),
$select('id_kbfos', 'Kirby Bauer FOS', array_merge(['Tidak dilakukan'], range(1, 42))),
$select('id_sirkbfos', 'Kirby Bauer FOS SIR', ['S', 'I', 'R']),
$select('id_kbscf', 'Kirby Bauer SCF', array_merge(['Tidak dilakukan'], range(1, 42))),
$select('id_sirkbscf', 'Kirby Bauer SCF SIR', ['S', 'I', 'R']),
$select('id_biakankultur', 'Biakan Kultur (Aerob / Anaerob)', $organismOptions),
$select('media_bap_status', 'Media BAP Status', ['Ada Pertumbuhan', 'Tidak Ada Pertumbuhan', 'Pertumbuhan Primer']),
$text('media_bap_note', 'Media BAP Catatan'),
$select('media_cap_status', 'Media CAP Status', ['Ada Pertumbuhan', 'Tidak Ada Pertumbuhan', 'Pertumbuhan Primer']),
$text('media_cap_note', 'Media CAP Catatan'),
$select('media_mcconkey_status', 'Media Mc Conkey Status', ['Ada Pertumbuhan', 'Tidak Ada Pertumbuhan', 'Pertumbuhan Primer']),
$text('media_mcconkey_note', 'Media Mc Conkey Catatan'),
$select('media_sdar1_status', 'Kultur Jamur R1 Status', ['Ada Pertumbuhan', 'Tidak Ada Pertumbuhan', 'Pertumbuhan Primer']),
$text('media_sdar1_note', 'Kultur Jamur R1 Catatan'),
$select('media_sdar2_status', 'Kultur Jamur R2 Status', ['Ada Pertumbuhan', 'Tidak Ada Pertumbuhan', 'Pertumbuhan Primer']),
$text('media_sdar2_note', 'Kultur Jamur R2 Catatan'),
$select('media_sdai1_status', 'Kultur Jamur I1 Status', ['Ada Pertumbuhan', 'Tidak Ada Pertumbuhan', 'Pertumbuhan Primer']),
$text('media_sdai1_note', 'Kultur Jamur I1 Catatan'),
$select('media_sdai2_status', 'Kultur Jamur I2 Status', ['Ada Pertumbuhan', 'Tidak Ada Pertumbuhan', 'Pertumbuhan Primer']),
$text('media_sdai2_note', 'Kultur Jamur I2 Catatan'),
$select('media_sellainnya_status', 'Media Selektif Lainnya Status', ['Ada Pertumbuhan', 'Tidak Ada Pertumbuhan', 'Pertumbuhan Primer']),
$text('media_sellainnya_note', 'Media Selektif Lainnya Catatan'),
$select('media_tamlainnya_status', 'Pemeriksaan Tambahan Lainnya Status', ['Ada Pertumbuhan', 'Tidak Ada Pertumbuhan', 'Pertumbuhan Primer']),
$text('media_tamlainnya_note', 'Pemeriksaan Tambahan Lainnya Catatan'),
$text('bakteri', 'Vitek - Bakteri'),
$select('bakterisir', 'Vitek - SIR', $sirOptions),
$select('id_bakterihitungkol', 'Vitek - Hitung Koloni', $colonyOptions),
$text('id_bakterihitungkolteks', 'Vitek - Hitung Koloni Lainnya'),
$select('id_baktericetak', 'Vitek - Cetak', $printOptions),
$text('id_bakteri01', 'MALDITOF - Bakteri'),
$text('id_antibiotikmanual1', 'MALDITOF - Set Antibiotik'),
$select('id_bakterisir01', 'MALDITOF - SIR', $sirOptions),
$select('id_bakterihitungkol01', 'MALDITOF - Hitung Koloni', $colonyOptions),
$text('id_bakterihitungkolteks01', 'MALDITOF - Hitung Koloni Lainnya'),
$select('id_bakteri01cetak', 'MALDITOF - Cetak', $printOptions),
$text('id_bakteri02', 'Bakteri Manual I - Bakteri'),
$text('id_antibiotikmanual2', 'Bakteri Manual I - Set Antibiotik'),
$select('id_bakterisir02', 'Bakteri Manual I - SIR', $sirOptions),
$select('id_bakterihitungkol02', 'Bakteri Manual I - Hitung Koloni', $colonyOptions),
$text('id_bakterihitungkolteks02', 'Bakteri Manual I - Hitung Koloni Lainnya'),
$select('id_bakteri02cetak', 'Bakteri Manual I - Cetak', $printOptions),
$area('keterangan', 'Keterangan Expertise'),
],
'Pewarna Langsung' => [
$select('lsg_selepitel', 'Sel Epitel', $organismOptions),
$select('lsg_selradang', 'Sel Radang', $organismOptions),
$select('lsg_mikroorganisme', 'Mikroorganisme', $organismOptions),
$multi('lsg_mikroorganismeoptional', 'Mikroorganisme Tambahan', ['Gram positif', 'Gram negatif', 'Yeast cell', 'Basil', 'Kokus']),
$select('lsg_pewarnaanziehlnielsen', 'Pewarnaan Ziehl Neelsen Pagi', $organismOptions),
$select('lsg_pewarnaanziehlnielsensewaktu', 'Pewarnaan Ziehl Neelsen Sewaktu', $organismOptions),
$select('lsg_pewarnaankoh', 'Pewarnaan KOH', ['Tidak ditemukan', 'Ditemukan', 'lainnya']),
$text('lsg_pewarnaankohoptional', 'Pewarnaan KOH Lainnya'),
$select('lsg_pewarnaanneisser', 'Pewarnaan Neisser', $organismOptions),
$select('lsg_pewarnaannegatif', 'Pewarnaan Negatif', $organismOptions),
$select('lsg_pewarnaangiesma', 'Pewarnaan Giemsa', ['Tidak ditemukan', 'Ditemukan', 'lainnya']),
$text('lsg_pewarnaangiesmaoptional', 'Pewarnaan Giemsa Lainnya'),
$select('lsg_pewarnaanspora', 'Pewarnaan Spora', $organismOptions),
$area('lsg_pewarnaanlain', 'Pewarnaan Lain'),
$select('lsg_jumlahlactobacillus', 'Lactobacillus - Jumlah Per Lapang', $organismOptions),
$select('lsg_lactobacillus', 'Lactobacillus - Skor', ['0', '1', '2', '3', '4']),
$select('lsg_jumlahgardnerella', 'Gardnerella - Jumlah Per Lapang', $organismOptions),
$select('lsg_gardnerella', 'Gardnerella - Skor', ['0', '1', '2', '3', '4']),
$select('lsg_jumlahmobiluncus', 'Mobiluncus - Jumlah Per Lapang', $organismOptions),
$select('lsg_mobiluncus', 'Mobiluncus - Skor', ['0', '1', '2', '3', '4']),
$select('media_bap_status', 'Media BAP Status', ['Ada Pertumbuhan', 'Tidak Ada Pertumbuhan', 'Pertumbuhan Primer']),
$text('media_bap_note', 'Media BAP Catatan'),
$select('media_cap_status', 'Media CAP Status', ['Ada Pertumbuhan', 'Tidak Ada Pertumbuhan', 'Pertumbuhan Primer']),
$text('media_cap_note', 'Media CAP Catatan'),
$select('media_mcconkey_status', 'Media Mc Conkey Status', ['Ada Pertumbuhan', 'Tidak Ada Pertumbuhan', 'Pertumbuhan Primer']),
$text('media_mcconkey_note', 'Media Mc Conkey Catatan'),
$select('media_sdar1_status', 'Kultur Jamur R1 Status', ['Ada Pertumbuhan', 'Tidak Ada Pertumbuhan', 'Pertumbuhan Primer']),
$text('media_sdar1_note', 'Kultur Jamur R1 Catatan'),
$select('media_sdar2_status', 'Kultur Jamur R2 Status', ['Ada Pertumbuhan', 'Tidak Ada Pertumbuhan', 'Pertumbuhan Primer']),
$text('media_sdar2_note', 'Kultur Jamur R2 Catatan'),
$select('media_sdai1_status', 'Kultur Jamur I1 Status', ['Ada Pertumbuhan', 'Tidak Ada Pertumbuhan', 'Pertumbuhan Primer']),
$text('media_sdai1_note', 'Kultur Jamur I1 Catatan'),
$select('media_sdai2_status', 'Kultur Jamur I2 Status', ['Ada Pertumbuhan', 'Tidak Ada Pertumbuhan', 'Pertumbuhan Primer']),
$text('media_sdai2_note', 'Kultur Jamur I2 Catatan'),
$select('media_sellainnya_status', 'Media Selektif Lainnya Status', ['Ada Pertumbuhan', 'Tidak Ada Pertumbuhan', 'Pertumbuhan Primer']),
$text('media_sellainnya_note', 'Media Selektif Lainnya Catatan'),
$select('media_tamlainnya_status', 'Pemeriksaan Tambahan Lainnya Status', ['Ada Pertumbuhan', 'Tidak Ada Pertumbuhan', 'Pertumbuhan Primer']),
$text('media_tamlainnya_note', 'Pemeriksaan Tambahan Lainnya Catatan'),
$text('bakteri', 'Vitek - Bakteri'),
$select('bakterisir', 'Vitek - SIR', $sirOptions),
$select('id_bakterihitungkol', 'Vitek - Hitung Koloni', $colonyOptions),
$text('id_bakterihitungkolteks', 'Vitek - Hitung Koloni Lainnya'),
$select('id_baktericetak', 'Vitek - Cetak', $printOptions),
$text('id_bakteri01', 'MALDITOF - Bakteri'),
$text('id_antibiotikmanual1', 'MALDITOF - Set Antibiotik'),
$select('id_bakterisir01', 'MALDITOF - SIR', $sirOptions),
$select('id_bakterihitungkol01', 'MALDITOF - Hitung Koloni', $colonyOptions),
$text('id_bakterihitungkolteks01', 'MALDITOF - Hitung Koloni Lainnya'),
$select('id_bakteri01cetak', 'MALDITOF - Cetak', $printOptions),
$text('id_bakteri02', 'Bakteri Manual I - Bakteri'),
$text('id_antibiotikmanual2', 'Bakteri Manual I - Set Antibiotik'),
$select('id_bakterisir02', 'Bakteri Manual I - SIR', $sirOptions),
$select('id_bakterihitungkol02', 'Bakteri Manual I - Hitung Koloni', $colonyOptions),
$text('id_bakterihitungkolteks02', 'Bakteri Manual I - Hitung Koloni Lainnya'),
$select('id_bakteri02cetak', 'Bakteri Manual I - Cetak', $printOptions),
$area('keterangan', 'Keterangan Expertise'),
],
'TBC' => [
$multi('jenis_pasien_tbc', 'Jenis Terduga / Pasien TBC', ['TBC SO', 'TBC RO', 'Anak', 'HIV', 'DM']),
$text('id_noidsediaan', 'No. Identitas Sediaan'),
$text('id_tanggalpengambilancontohuji', 'Tanggal Pengambilan Contoh Uji'),
$text('id_tanggalpengirimancontohuji', 'Tanggal Pengiriman Contoh Uji'),
$select('id_lamariwayatpengobatantb', 'Lama Riwayat Pengobatan TBC', ['Riwayat Pengobatan >= 5 tahun', 'Riwayat Pengobatan < 5 tahun']),
$select('id_jenispemeriksaantb', 'Jenis Pemeriksaan', ['Mikroskopis', 'TCM MTB Rif (Xpert)', 'TCM XDR (Xpert)', 'TCM MTB Rif (Truenat)', 'TCM MTB Rif INH (BDMAX)', 'PCR Open System', 'LPA lini 1', 'LPA lini 2', 'Biakan', 'Paket standar uji kepekaan']),
$select('id_lokasianatomi', 'Lokasi Anatomi', ['Paru', 'Ekstraparu']),
$text('id_ekstraparu', 'Ekstraparu'),
$select('id_alasanpemeriksaan', 'Alasan Pemeriksaan', ['Diagnosis TBC', 'Diagnosis Baseline TBC', 'Akhir Pengobatan']),
$text('id_bulankemajuantbfollow', 'Pemantauan kemajuan pengobatan'),
$text('id_bulanpemeriksaanulang', 'Pemeriksaan ulang'),
$text('id_bulanpemeriksaansetelahselesai', 'Pemeriksaan setelah selesai pengobatan'),
$text('id_noregfasyankes', 'No.Reg.TBC/TBC RO Fasyankes'),
$text('id_noregkota', 'No.Reg.TBC/TBC RO Kab/Kota'),
$select('id_contohuji', 'Contoh Uji', ['Dahak', 'Lainnya']),
$text('id_contohujilainnya', 'Contoh Uji Lainnya'),
$multi('visual_dahak_sewaktu', 'Visual dahak Sewaktu', ['Nanah Lendir', 'Bercak darah', 'Air liur']),
$multi('visual_dahak_pagi', 'Visual dahak Pagi', ['Nanah Lendir', 'Bercak darah', 'Air liur']),
$text('hasilpemeriksaantmikroskopis_tglsewaktu', 'Tanggal Mikroskopis Sewaktu'),
$select('hasilpemeriksaantmikroskopis_hasilsewaktu', 'Mikroskopis Sewaktu', $tbResult),
$text('hasilpemeriksaantmikroskopis_tglpagi', 'Tanggal Mikroskopis Pagi'),
$select('hasilpemeriksaantmikroskopis_hasilpagi', 'Mikroskopis Pagi', $tbResult),
$text('hasilpemeriksaanttcmmtbrifxpert_tglsewaktu', 'Tanggal TCM MTB Rif Sewaktu'),
$text('hasilpemeriksaanttcmmtbrifxpert_kodeunik', 'Kode Unik TCM MTB Rif Sewaktu'),
$select('hasilpemeriksaanttcmmtbrifxpert_hasilsewaktu', 'TCM MTB Rif Sewaktu', ['Neg', 'Rif Sen', 'Rif Res', 'Rif Indet', 'Invalid', 'Error', 'No result']),
$text('hasilpemeriksaanttcmmtbrifxpert_tglpagi', 'Tanggal TCM MTB Rif Pagi'),
$text('hasilpemeriksaanttcmmtbrifxpert_kodeunikpagi', 'Kode Unik TCM MTB Rif Pagi'),
$select('hasilpemeriksaanttcmmtbrifxpert_hasilpagi', 'TCM MTB Rif Pagi', ['Neg', 'Rif Sen', 'Rif Res', 'Rif Indet', 'Invalid', 'Error', 'No result']),
$text('hasilpemeriksaantbbiakan_tgl', 'Tanggal Mikroskopis Biakan'),
$select('hasilpemeriksaantbbiakan_pagi', 'Biakan Mikroskopis Pagi', $tbResult),
$select('hasilpemeriksaantbbiakan_sewaktu', 'Biakan Mikroskopis Sewaktu', $tbResult),
$text('hasilpemeriksaantbbiakan_tglbiakan', 'Tanggal Biakan'),
$select('hasilpemeriksaantbbiakan_hasilbiakanmgit', 'Hasil Biakan MGIT', ['Pos', 'Neg', 'NTM', 'KTM', 'TDL']),
$select('hasilpemeriksaantbbiakan_hasilbiakanlj', 'Hasil Biakan LJ', ['3+', '2+', '1+', '1-9', 'Neg', 'NTM', 'KTM', 'TDL']),
$text('hasilpemeriksaanttcmmtbxdrxpert_tglpagi', 'Tanggal TCM XDR Pagi'),
$text('hasilpemeriksaanttcmmtbxdrxpert_kodeunikpagi', 'Kode Unik TCM XDR Pagi'),
$text('hasilpemeriksaanttcmmtbxdrxpert_tglsewaktu', 'Tanggal TCM XDR Sewaktu'),
$text('hasilpemeriksaanttcmmtbxdrxpert_kodeunik', 'Kode Unik TCM XDR Sewaktu'),
$select('hasilpemeriksaanttcmmtbxdrxpert_pagi', 'TCM XDR Pagi', ['Valid', 'Invalid', 'No Result', 'Error']),
$select('hasilpemeriksaanttcmmtbxdrxpert_pagimtb', 'MTB Pagi', ['Detected', 'Not Detected']),
$select('hasilpemeriksaanttcmmtbxdrxpert_paginhlow', 'H Low Pagi', ['S', 'I', 'R', 'Invalid', 'Error', 'No Result']),
$select('hasilpemeriksaanttcmmtbxdrxpert_pagih', 'H Pagi', ['S', 'I', 'R', 'Invalid', 'Error', 'No Result']),
$select('hasilpemeriksaanttcmmtbxdrxpert_pagifqlow', 'FQ Low Pagi', ['S', 'I', 'R', 'Invalid', 'Error', 'No Result']),
$select('hasilpemeriksaanttcmmtbxdrxpert_pagifq', 'FQ Pagi', ['S', 'I', 'R', 'Invalid', 'Error', 'No Result']),
$select('hasilpemeriksaanttcmmtbxdrxpert_pagiamk', 'Amk Pagi', ['S', 'I', 'R', 'Invalid', 'Error', 'No Result']),
$select('hasilpemeriksaanttcmmtbxdrxpert_pagikm', 'Km Pagi', ['S', 'I', 'R', 'Invalid', 'Error', 'No Result']),
$select('hasilpemeriksaanttcmmtbxdrxpert_pagicm', 'Cm Pagi', ['S', 'I', 'R', 'Invalid', 'Error', 'No Result']),
$select('hasilpemeriksaanttcmmtbxdrxpert_pagieto', 'Eto Pagi', ['S', 'I', 'R', 'Invalid', 'Error', 'No Result']),
$select('hasilpemeriksaanttcmmtbxdrxpert_sewaktu', 'TCM XDR Sewaktu', ['Valid', 'Invalid', 'No Result', 'Error']),
$select('hasilpemeriksaanttcmmtbxdrxpert_sewaktumtb', 'MTB Sewaktu', ['Detected', 'Not Detected']),
$select('hasilpemeriksaanttcmmtbxdrxpert_sewaktunhlow', 'H Low Sewaktu', ['S', 'I', 'R', 'Invalid', 'Error', 'No Result']),
$select('hasilpemeriksaanttcmmtbxdrxpert_sewaktuh', 'H Sewaktu', ['S', 'I', 'R', 'Invalid', 'Error', 'No Result']),
$select('hasilpemeriksaanttcmmtbxdrxpert_sewaktufqlow', 'FQ Low Sewaktu', ['S', 'I', 'R', 'Invalid', 'Error', 'No Result']),
$select('hasilpemeriksaanttcmmtbxdrxpert_sewaktufq', 'FQ Sewaktu', ['S', 'I', 'R', 'Invalid', 'Error', 'No Result']),
$select('hasilpemeriksaanttcmmtbxdrxpert_sewaktuamk', 'Amk Sewaktu', ['S', 'I', 'R', 'Invalid', 'Error', 'No Result']),
$select('hasilpemeriksaanttcmmtbxdrxpert_sewaktukm', 'Km Sewaktu', ['S', 'I', 'R', 'Invalid', 'Error', 'No Result']),
$select('hasilpemeriksaanttcmmtbxdrxpert_sewaktucm', 'Cm Sewaktu', ['S', 'I', 'R', 'Invalid', 'Error', 'No Result']),
$select('hasilpemeriksaanttcmmtbxdrxpert_sewaktueto', 'Eto Sewaktu', ['S', 'I', 'R', 'Invalid', 'Error', 'No Result']),
$select('media_bap_status', 'Media BAP Status', ['Ada Pertumbuhan', 'Tidak Ada Pertumbuhan', 'Pertumbuhan Primer']),
$text('media_bap_note', 'Media BAP Catatan'),
$select('media_cap_status', 'Media CAP Status', ['Ada Pertumbuhan', 'Tidak Ada Pertumbuhan', 'Pertumbuhan Primer']),
$text('media_cap_note', 'Media CAP Catatan'),
$select('media_mcconkey_status', 'Media Mc Conkey Status', ['Ada Pertumbuhan', 'Tidak Ada Pertumbuhan', 'Pertumbuhan Primer']),
$text('media_mcconkey_note', 'Media Mc Conkey Catatan'),
$select('media_sdar1_status', 'Kultur Jamur R1 Status', ['Ada Pertumbuhan', 'Tidak Ada Pertumbuhan', 'Pertumbuhan Primer']),
$text('media_sdar1_note', 'Kultur Jamur R1 Catatan'),
$select('media_sdar2_status', 'Kultur Jamur R2 Status', ['Ada Pertumbuhan', 'Tidak Ada Pertumbuhan', 'Pertumbuhan Primer']),
$text('media_sdar2_note', 'Kultur Jamur R2 Catatan'),
$select('media_sdai1_status', 'Kultur Jamur I1 Status', ['Ada Pertumbuhan', 'Tidak Ada Pertumbuhan', 'Pertumbuhan Primer']),
$text('media_sdai1_note', 'Kultur Jamur I1 Catatan'),
$select('media_sdai2_status', 'Kultur Jamur I2 Status', ['Ada Pertumbuhan', 'Tidak Ada Pertumbuhan', 'Pertumbuhan Primer']),
$text('media_sdai2_note', 'Kultur Jamur I2 Catatan'),
$select('media_sellainnya_status', 'Media Selektif Lainnya Status', ['Ada Pertumbuhan', 'Tidak Ada Pertumbuhan', 'Pertumbuhan Primer']),
$text('media_sellainnya_note', 'Media Selektif Lainnya Catatan'),
$select('media_tamlainnya_status', 'Pemeriksaan Tambahan Lainnya Status', ['Ada Pertumbuhan', 'Tidak Ada Pertumbuhan', 'Pertumbuhan Primer']),
$text('media_tamlainnya_note', 'Pemeriksaan Tambahan Lainnya Catatan'),
$text('bakteri', 'Vitek - Bakteri'),
$select('bakterisir', 'Vitek - SIR', $sirOptions),
$select('id_bakterihitungkol', 'Vitek - Hitung Koloni', $colonyOptions),
$text('id_bakterihitungkolteks', 'Vitek - Hitung Koloni Lainnya'),
$select('id_baktericetak', 'Vitek - Cetak', $printOptions),
$text('id_bakteri01', 'MALDITOF - Bakteri'),
$text('id_antibiotikmanual1', 'MALDITOF - Set Antibiotik'),
$select('id_bakterisir01', 'MALDITOF - SIR', $sirOptions),
$select('id_bakterihitungkol01', 'MALDITOF - Hitung Koloni', $colonyOptions),
$text('id_bakterihitungkolteks01', 'MALDITOF - Hitung Koloni Lainnya'),
$select('id_bakteri01cetak', 'MALDITOF - Cetak', $printOptions),
$text('id_bakteri02', 'Bakteri Manual I - Bakteri'),
$text('id_antibiotikmanual2', 'Bakteri Manual I - Set Antibiotik'),
$select('id_bakterisir02', 'Bakteri Manual I - SIR', $sirOptions),
$select('id_bakterihitungkol02', 'Bakteri Manual I - Hitung Koloni', $colonyOptions),
$text('id_bakterihitungkolteks02', 'Bakteri Manual I - Hitung Koloni Lainnya'),
$select('id_bakteri02cetak', 'Bakteri Manual I - Cetak', $printOptions),
$area('keterangan', 'Keterangan Expertise'),
],
'Viral Load' => [
$select('vl_parameter01', 'Parameter', ['HIV RNA', 'HCV RNA', 'HBV DNA']),
$select('vl_hasil01', 'Hasil', ['NOT DETECTED', '<40', '<1.60', '40', '41', '44', '45', '145', '<10', '20', '322', '511', '144', '211', 'lainnya']),
$text('vl_hasil01teks', 'Hasil Lainnya'),
$select('vl_satuan01', 'Satuan', ['copies/mL', 'IU/mL']),
$select('vl_rujukan01', 'Nilai Rujukan', ['40-10.000.000', '10-100.000.000']),
$select('vl_parameter02', 'Parameter 02', ['LOG']),
$select('vl_hasil02', 'Hasil 02', ['NOT DETECTED', '<1,60', '<1,85', '1,60', '1,61', '1,64', '1,65', '2,16', '1,00', '1,30', '2,51', '2,71', '2,34', 'lainnya']),
$text('vl_hasil02teks', 'Hasil 02 Lainnya'),
$select('vl_satuan02', 'Satuan 02', ['LOG']),
$select('vl_rujukan02', 'Nilai Rujukan 02', ['1,6-7', ' ']),
$area('viralload', 'Catatan Viral Load'),
$select('media_bap_status', 'Media BAP Status', ['Ada Pertumbuhan', 'Tidak Ada Pertumbuhan', 'Pertumbuhan Primer']),
$text('media_bap_note', 'Media BAP Catatan'),
$select('media_cap_status', 'Media CAP Status', ['Ada Pertumbuhan', 'Tidak Ada Pertumbuhan', 'Pertumbuhan Primer']),
$text('media_cap_note', 'Media CAP Catatan'),
$select('media_mcconkey_status', 'Media Mc Conkey Status', ['Ada Pertumbuhan', 'Tidak Ada Pertumbuhan', 'Pertumbuhan Primer']),
$text('media_mcconkey_note', 'Media Mc Conkey Catatan'),
$select('media_sdar1_status', 'Kultur Jamur R1 Status', ['Ada Pertumbuhan', 'Tidak Ada Pertumbuhan', 'Pertumbuhan Primer']),
$text('media_sdar1_note', 'Kultur Jamur R1 Catatan'),
$select('media_sdar2_status', 'Kultur Jamur R2 Status', ['Ada Pertumbuhan', 'Tidak Ada Pertumbuhan', 'Pertumbuhan Primer']),
$text('media_sdar2_note', 'Kultur Jamur R2 Catatan'),
$select('media_sdai1_status', 'Kultur Jamur I1 Status', ['Ada Pertumbuhan', 'Tidak Ada Pertumbuhan', 'Pertumbuhan Primer']),
$text('media_sdai1_note', 'Kultur Jamur I1 Catatan'),
$select('media_sdai2_status', 'Kultur Jamur I2 Status', ['Ada Pertumbuhan', 'Tidak Ada Pertumbuhan', 'Pertumbuhan Primer']),
$text('media_sdai2_note', 'Kultur Jamur I2 Catatan'),
$select('media_sellainnya_status', 'Media Selektif Lainnya Status', ['Ada Pertumbuhan', 'Tidak Ada Pertumbuhan', 'Pertumbuhan Primer']),
$text('media_sellainnya_note', 'Media Selektif Lainnya Catatan'),
$select('media_tamlainnya_status', 'Pemeriksaan Tambahan Lainnya Status', ['Ada Pertumbuhan', 'Tidak Ada Pertumbuhan', 'Pertumbuhan Primer']),
$text('media_tamlainnya_note', 'Pemeriksaan Tambahan Lainnya Catatan'),
$text('bakteri', 'Vitek - Bakteri'),
$select('bakterisir', 'Vitek - SIR', $sirOptions),
$select('id_bakterihitungkol', 'Vitek - Hitung Koloni', $colonyOptions),
$text('id_bakterihitungkolteks', 'Vitek - Hitung Koloni Lainnya'),
$select('id_baktericetak', 'Vitek - Cetak', $printOptions),
$text('id_bakteri01', 'MALDITOF - Bakteri'),
$text('id_antibiotikmanual1', 'MALDITOF - Set Antibiotik'),
$select('id_bakterisir01', 'MALDITOF - SIR', $sirOptions),
$select('id_bakterihitungkol01', 'MALDITOF - Hitung Koloni', $colonyOptions),
$text('id_bakterihitungkolteks01', 'MALDITOF - Hitung Koloni Lainnya'),
$select('id_bakteri01cetak', 'MALDITOF - Cetak', $printOptions),
$text('id_bakteri02', 'Bakteri Manual I - Bakteri'),
$text('id_antibiotikmanual2', 'Bakteri Manual I - Set Antibiotik'),
$select('id_bakterisir02', 'Bakteri Manual I - SIR', $sirOptions),
$select('id_bakterihitungkol02', 'Bakteri Manual I - Hitung Koloni', $colonyOptions),
$text('id_bakterihitungkolteks02', 'Bakteri Manual I - Hitung Koloni Lainnya'),
$select('id_bakteri02cetak', 'Bakteri Manual I - Cetak', $printOptions),
$area('keterangan', 'Keterangan Expertise'),
],
'IgM IgG Leptospira' => [
$select('igg_parameter', 'IgG Leptospira', $yn),
$select('igm_parameter', 'IgM Leptospira', $yn),
$area('iggigm_interpretasi', 'Interpretasi'),
$select('media_bap_status', 'Media BAP Status', ['Ada Pertumbuhan', 'Tidak Ada Pertumbuhan', 'Pertumbuhan Primer']),
$text('media_bap_note', 'Media BAP Catatan'),
$select('media_cap_status', 'Media CAP Status', ['Ada Pertumbuhan', 'Tidak Ada Pertumbuhan', 'Pertumbuhan Primer']),
$text('media_cap_note', 'Media CAP Catatan'),
$select('media_mcconkey_status', 'Media Mc Conkey Status', ['Ada Pertumbuhan', 'Tidak Ada Pertumbuhan', 'Pertumbuhan Primer']),
$text('media_mcconkey_note', 'Media Mc Conkey Catatan'),
$select('media_sdar1_status', 'Kultur Jamur R1 Status', ['Ada Pertumbuhan', 'Tidak Ada Pertumbuhan', 'Pertumbuhan Primer']),
$text('media_sdar1_note', 'Kultur Jamur R1 Catatan'),
$select('media_sdar2_status', 'Kultur Jamur R2 Status', ['Ada Pertumbuhan', 'Tidak Ada Pertumbuhan', 'Pertumbuhan Primer']),
$text('media_sdar2_note', 'Kultur Jamur R2 Catatan'),
$select('media_sdai1_status', 'Kultur Jamur I1 Status', ['Ada Pertumbuhan', 'Tidak Ada Pertumbuhan', 'Pertumbuhan Primer']),
$text('media_sdai1_note', 'Kultur Jamur I1 Catatan'),
$select('media_sdai2_status', 'Kultur Jamur I2 Status', ['Ada Pertumbuhan', 'Tidak Ada Pertumbuhan', 'Pertumbuhan Primer']),
$text('media_sdai2_note', 'Kultur Jamur I2 Catatan'),
$select('media_sellainnya_status', 'Media Selektif Lainnya Status', ['Ada Pertumbuhan', 'Tidak Ada Pertumbuhan', 'Pertumbuhan Primer']),
$text('media_sellainnya_note', 'Media Selektif Lainnya Catatan'),
$select('media_tamlainnya_status', 'Pemeriksaan Tambahan Lainnya Status', ['Ada Pertumbuhan', 'Tidak Ada Pertumbuhan', 'Pertumbuhan Primer']),
$text('media_tamlainnya_note', 'Pemeriksaan Tambahan Lainnya Catatan'),
$text('bakteri', 'Vitek - Bakteri'),
$select('bakterisir', 'Vitek - SIR', $sirOptions),
$select('id_bakterihitungkol', 'Vitek - Hitung Koloni', $colonyOptions),
$text('id_bakterihitungkolteks', 'Vitek - Hitung Koloni Lainnya'),
$select('id_baktericetak', 'Vitek - Cetak', $printOptions),
$text('id_bakteri01', 'MALDITOF - Bakteri'),
$text('id_antibiotikmanual1', 'MALDITOF - Set Antibiotik'),
$select('id_bakterisir01', 'MALDITOF - SIR', $sirOptions),
$select('id_bakterihitungkol01', 'MALDITOF - Hitung Koloni', $colonyOptions),
$text('id_bakterihitungkolteks01', 'MALDITOF - Hitung Koloni Lainnya'),
$select('id_bakteri01cetak', 'MALDITOF - Cetak', $printOptions),
$text('id_bakteri02', 'Bakteri Manual I - Bakteri'),
$text('id_antibiotikmanual2', 'Bakteri Manual I - Set Antibiotik'),
$select('id_bakterisir02', 'Bakteri Manual I - SIR', $sirOptions),
$select('id_bakterihitungkol02', 'Bakteri Manual I - Hitung Koloni', $colonyOptions),
$text('id_bakterihitungkolteks02', 'Bakteri Manual I - Hitung Koloni Lainnya'),
$select('id_bakteri02cetak', 'Bakteri Manual I - Cetak', $printOptions),
$area('keterangan', 'Keterangan Expertise'),
],
'PCR COVID' => [
$select('covid_virus01', 'Virus SARS-Cov-2', ['Positif', 'Negatif', 'Tidak Diperiksa']),
$text('covid_satuanvirus01', 'Satuan SARS-Cov-2'),
$text('covid_rujukanvirus01', 'Nilai Rujukan SARS-Cov-2'),
$select('covid_virus02', 'Influenza A', ['Positif', 'Negatif', 'Tidak Diperiksa']),
$text('covid_satuanvirus02', 'Satuan Influenza A'),
$text('covid_rujukanvirus02', 'Nilai Rujukan Influenza A'),
$select('covid_virus03', 'Influenza B', ['Positif', 'Negatif', 'Tidak Diperiksa']),
$text('covid_satuanvirus03', 'Satuan Influenza B'),
$text('covid_rujukanvirus03', 'Nilai Rujukan Influenza B'),
$select('covid_virus04', 'RSV', ['Positif', 'Negatif', 'Tidak Diperiksa']),
$text('covid_satuanvirus04', 'Satuan RSV'),
$text('covid_rujukanvirus04', 'Nilai Rujukan RSV'),
$area('covid_interpretasi', 'Interpretasi'),
$select('media_bap_status', 'Media BAP Status', ['Ada Pertumbuhan', 'Tidak Ada Pertumbuhan', 'Pertumbuhan Primer']),
$text('media_bap_note', 'Media BAP Catatan'),
$select('media_cap_status', 'Media CAP Status', ['Ada Pertumbuhan', 'Tidak Ada Pertumbuhan', 'Pertumbuhan Primer']),
$text('media_cap_note', 'Media CAP Catatan'),
$select('media_mcconkey_status', 'Media Mc Conkey Status', ['Ada Pertumbuhan', 'Tidak Ada Pertumbuhan', 'Pertumbuhan Primer']),
$text('media_mcconkey_note', 'Media Mc Conkey Catatan'),
$select('media_sdar1_status', 'Kultur Jamur R1 Status', ['Ada Pertumbuhan', 'Tidak Ada Pertumbuhan', 'Pertumbuhan Primer']),
$text('media_sdar1_note', 'Kultur Jamur R1 Catatan'),
$select('media_sdar2_status', 'Kultur Jamur R2 Status', ['Ada Pertumbuhan', 'Tidak Ada Pertumbuhan', 'Pertumbuhan Primer']),
$text('media_sdar2_note', 'Kultur Jamur R2 Catatan'),
$select('media_sdai1_status', 'Kultur Jamur I1 Status', ['Ada Pertumbuhan', 'Tidak Ada Pertumbuhan', 'Pertumbuhan Primer']),
$text('media_sdai1_note', 'Kultur Jamur I1 Catatan'),
$select('media_sdai2_status', 'Kultur Jamur I2 Status', ['Ada Pertumbuhan', 'Tidak Ada Pertumbuhan', 'Pertumbuhan Primer']),
$text('media_sdai2_note', 'Kultur Jamur I2 Catatan'),
$select('media_sellainnya_status', 'Media Selektif Lainnya Status', ['Ada Pertumbuhan', 'Tidak Ada Pertumbuhan', 'Pertumbuhan Primer']),
$text('media_sellainnya_note', 'Media Selektif Lainnya Catatan'),
$select('media_tamlainnya_status', 'Pemeriksaan Tambahan Lainnya Status', ['Ada Pertumbuhan', 'Tidak Ada Pertumbuhan', 'Pertumbuhan Primer']),
$text('media_tamlainnya_note', 'Pemeriksaan Tambahan Lainnya Catatan'),
$text('bakteri', 'Vitek - Bakteri'),
$select('bakterisir', 'Vitek - SIR', $sirOptions),
$select('id_bakterihitungkol', 'Vitek - Hitung Koloni', $colonyOptions),
$text('id_bakterihitungkolteks', 'Vitek - Hitung Koloni Lainnya'),
$select('id_baktericetak', 'Vitek - Cetak', $printOptions),
$text('id_bakteri01', 'MALDITOF - Bakteri'),
$text('id_antibiotikmanual1', 'MALDITOF - Set Antibiotik'),
$select('id_bakterisir01', 'MALDITOF - SIR', $sirOptions),
$select('id_bakterihitungkol01', 'MALDITOF - Hitung Koloni', $colonyOptions),
$text('id_bakterihitungkolteks01', 'MALDITOF - Hitung Koloni Lainnya'),
$select('id_bakteri01cetak', 'MALDITOF - Cetak', $printOptions),
$text('id_bakteri02', 'Bakteri Manual I - Bakteri'),
$text('id_antibiotikmanual2', 'Bakteri Manual I - Set Antibiotik'),
$select('id_bakterisir02', 'Bakteri Manual I - SIR', $sirOptions),
$select('id_bakterihitungkol02', 'Bakteri Manual I - Hitung Koloni', $colonyOptions),
$text('id_bakterihitungkolteks02', 'Bakteri Manual I - Hitung Koloni Lainnya'),
$select('id_bakteri02cetak', 'Bakteri Manual I - Cetak', $printOptions),
$area('keterangan', 'Keterangan Expertise'),
],
default => [
$area('keterangan', 'Keterangan Expertise'),
],
};
}
protected function resolvePeriksaHierarchyStatus($currentStatus, $proposedStatus): string
{
$currentStatus = trim((string) $currentStatus);
$proposedStatus = trim((string) $proposedStatus);
if ($proposedStatus === '') {
return $currentStatus;
}
$currentRank = $this->periksaHierarchyStatusRank($currentStatus);
$proposedRank = $this->periksaHierarchyStatusRank($proposedStatus);
if ($currentStatus === '') {
return $proposedStatus;
}
if ($proposedRank === null) {
return $currentRank === null ? $proposedStatus : $currentStatus;
}
if ($currentRank === null || $proposedRank >= $currentRank) {
return $proposedStatus;
}
return $currentStatus;
}
protected function periksaHierarchyStatusRank($status): ?int
{
$normalized = $this->normalizePeriksaStatus($status);
if ($normalized === '') {
return null;
}
if ($normalized === 'penerimaan sampel') {
return 1;
}
if (in_array($normalized, ['pemeriksaan awal', 'pemeriksaan sampel', 'proses analisis sampel'], true)) {
return 2;
}
if (str_starts_with($normalized, 'data bd di terima') || str_starts_with($normalized, 'data bd diterima')) {
return 3;
}
if ($normalized === 'pewarnaan langsung') {
return 4;
}
if ($this->isProsesingKoloniMediaStatus($normalized)) {
return 5;
}
if (str_starts_with($normalized, 'data malditof diterima') || str_starts_with($normalized, 'data malditof di terima')) {
return 6;
}
if (str_starts_with($normalized, 'otor maldi (un verified)')) {
return 7;
}
if (str_starts_with($normalized, 'preliminary results')) {
return 8;
}
if (str_starts_with($normalized, 'data vitek di terima') || str_starts_with($normalized, 'data vitek diterima')) {
return 9;
}
if (str_starts_with($normalized, 'id/ast pending result') || $normalized === 'sedang id+ast') {
return 10;
}
if (str_starts_with($normalized, 'expertise saved (un verified)')
|| in_array($normalized, ['expertise', 'selesai', 'final result'], true)) {
return 11;
}
return null;
}
protected function normalizePeriksaStatus($status): string
{
$status = strtolower(trim((string) $status));
$status = str_replace(['_', '-'], ' ', $status);
$status = preg_replace('/\s+/', ' ', $status);
return trim($status);
}
protected function isProsesingKoloniMediaStatus(string $normalizedStatus): bool
{
$exactStatuses = [
'tidak ada pertumbuhan',
'tidak lanjut identifikasi',
'tidak tindak lanjut identifikasi',
'inkubasi lanjutan',
'sub kultur',
'menunggu kultur yg lain',
'menunggu kultur yang lain',
'proses identifikasi dan uji kepekaan',
'sedang malditof',
'pertumbuhan primer',
];
if (in_array($normalizedStatus, $exactStatuses, true)) {
return true;
}
return str_starts_with($normalizedStatus, 'prosesing koloni media')
|| str_starts_with($normalizedStatus, 'processing koloni media')
|| str_starts_with($normalizedStatus, 'proses identifikasi')
|| str_starts_with($normalizedStatus, 'proses uji kepekaan');
}
public function earlyWarning(Request $request)
{
$this->requireUser($request);
return response()->json(['groups' => $this->earlyWarningGroups()]);
}
protected function earlyWarningGroups(): array
{
$now = Carbon::now();
$rows = Periksa::leftJoin('poli', 'periksa.poli_id', '=', 'poli.id')
->select('periksa.id', 'periksa.poli_id', 'periksa.nofoto', 'periksa.noregister', 'periksa.nmpasien', 'periksa.reques', 'periksa.asalpasien', 'periksa.daftar', 'periksa.status', 'poli.subpoli', 'poli.modaliti2')
->whereNotNull('periksa.status')
->where('periksa.status', '<>', '')
->whereRaw('LOWER(periksa.status) <> ?', ['selesai'])
->whereRaw('LOWER(periksa.status) not like ?', ['%dibatalkan%'])
->whereNotNull('periksa.daftar')
->orderBy('periksa.daftar', 'ASC')
->get();
$warnings = [];
foreach ($rows as $row) {
$targetDays = $this->resolveTargetDays($row->modaliti2);
$registeredAt = Carbon::parse($row->daftar);
$deadline = $registeredAt->copy()->addDays($targetDays)->endOfDay();
$remainingMinutes = $now->diffInMinutes($deadline, false);
$warningLimit = $targetDays > 1 ? 1440 : 60;
$isOverdue = $now->gt($deadline);
if ($isOverdue || $remainingMinutes <= $warningLimit) {
$warnings[] = array_merge($this->examinationPayload($row), [
'subpoli' => $row->subpoli ?? 'Tanpa Subpoli',
'target_hari' => $targetDays,
'target_selesai' => $deadline->format('Y-m-d H:i:s'),
'sisa_menit' => $remainingMinutes,
'warning_label' => $isOverdue ? 'Melewati Target' : ($targetDays > 1 ? 'Kurang dari 1 Hari' : 'Kurang dari 1 Jam'),
]);
}
}
return collect($warnings)
->groupBy(fn ($item) => $item['subpoli'] ?: 'Tanpa Subpoli')
->map(fn ($items, $subpoli) => [
'subpoli' => $subpoli,
'total' => count($items),
'items' => array_values($items->toArray()),
])
->values()
->toArray();
}
public function openExpertise(Request $request, int $periksa)
{
$token = (string) $request->query('token', '');
$request->headers->set('Authorization', 'Bearer '.$token);
$user = $this->userFromRequest($request);
abort_if(!$user, 401, 'Token login tidak valid.');
Auth::loginUsingId($user->id);
$photo = $user->getPhoto->xfile ?? '/doctor.png';
Session::put('id', $user->id);
Session::put('nama', $user->nama);
Session::put('username', $user->username);
Session::put('previlage', $user->previlage);
Session::put('photo', $photo);
Session::save();
return redirect()->route('mikro.expertise', ['periksa' => $periksa, 'return_to' => 'dashboard']);
}
}