update seed data dan fungsi pindah atau konsul klinik
This commit is contained in:
@@ -0,0 +1,321 @@
|
||||
# Mapping Data Structure ke ERD
|
||||
|
||||
Dokumen ini menjelaskan mapping antara struktur data pasien di `queueStore.js` (baris 607-622) ke tabel-tabel dalam ERD.
|
||||
|
||||
## Struktur Data di Code (queueStore.js)
|
||||
|
||||
```javascript
|
||||
{
|
||||
no: newNo,
|
||||
jamPanggil: "HH:MM",
|
||||
barcode: "26011395625",
|
||||
noAntrian: "KL0001 | Klinik - 26011395625",
|
||||
shift: "Shift 1",
|
||||
klinik: "KANDUNGAN",
|
||||
fastTrack: "TIDAK" | "YA",
|
||||
pembayaran: "BPJS" | "UMUM",
|
||||
status: "di-loket" | "waiting" | ...,
|
||||
processStage: "klinik" | "loket" | ...,
|
||||
createdAt: "2026-01-13T16:51:35.502Z",
|
||||
referencePatient: "UM1001 | Online - 26011395625" | null,
|
||||
loket: "Loket A" (optional),
|
||||
loketId: 1 (optional)
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Mapping ke Tabel ERD
|
||||
|
||||
### 1. **data_kunjungan_antrean** (Tabel Utama Kunjungan)
|
||||
|
||||
| Field Code | Field ERD | Keterangan |
|
||||
|------------|-----------|------------|
|
||||
| `barcode` | `Barcode` | Barcode unik pasien (string) |
|
||||
| `createdAt` | `Tanggal_daftar` | Tanggal dan waktu pendaftaran antrian |
|
||||
| - | `Pasien` | FK ke `data_pasien.id` (harus dicari/lookup berdasarkan barcode atau dibuat baru) |
|
||||
| - | `Tanggal_periksa` | Tanggal pemeriksaan (bisa sama dengan Tanggal_daftar atau null) |
|
||||
| - | `Tanggal_check_in` | Tanggal check-in (null jika belum check-in) |
|
||||
| - | `Check_in` | Status check-in (boolean/flag) |
|
||||
| - | `Surat_rujukan` | Surat rujukan (null jika tidak ada) |
|
||||
| - | `Surat_kontrol` | Surat kontrol (null jika tidak ada) |
|
||||
| - | `SEP` | SEP BPJS (null jika tidak ada) |
|
||||
| - | `Status_active` | Status aktif (default: 1 = Active) |
|
||||
|
||||
**Catatan:**
|
||||
- `barcode` langsung map ke field `Barcode`
|
||||
- `createdAt` map ke `Tanggal_daftar`
|
||||
- `referencePatient` bisa digunakan untuk tracking kunjungan sebelumnya (relasi ke `data_kunjungan_antrean` lain)
|
||||
|
||||
---
|
||||
|
||||
### 2. **data_kunjungan_tempat_layanan** (Detail Tempat Layanan)
|
||||
|
||||
| Field Code | Field ERD | Keterangan |
|
||||
|------------|-----------|------------|
|
||||
| `no` | `Nomor_tiket` | Nomor urut antrian (integer) |
|
||||
| `noAntrian` | - | Bisa disimpan sebagai informasi tambahan atau di-generate dari `Nomor_tiket` |
|
||||
| `klinik` | `Jenis_layanan` (?) | FK ke `data_jenis_layanan.id` (harus lookup berdasarkan nama klinik) |
|
||||
| `pembayaran` | `Penjamin` | FK ke `daftar_penjamin.id` (harus lookup: "BPJS" → id penjamin BPJS, "UMUM" → id penjamin UMUM) |
|
||||
| `loket` | `Loket` | FK ke `data_loket.id` (harus lookup berdasarkan nama loket) |
|
||||
| `loketId` | `Loket` | FK ke `data_loket.id` (jika ada, langsung gunakan) |
|
||||
| `fastTrack` | `Status_fasttrack` | FK ke lookup `ID: Status_fasttrack` (1 = True jika "YA", 0 = False jika "TIDAK") |
|
||||
| `fastTrack` | `Alasan_fasttrack` | Alasan fast track (string, bisa null jika "TIDAK") |
|
||||
| `processStage` | `Status_kunjungan` | FK ke lookup `ID: Status_kunjungan` (harus mapping: "loket" → 1, "klinik" → 2, dll) |
|
||||
| `shift` | - | Shift diambil dari `data_jenis_layanan_shift` berdasarkan jadwal |
|
||||
| - | `FK_kunjunganantrean_ten` | FK ke `data_kunjungan_antrean.id` |
|
||||
| - | `Jenis_kunjungan` | FK ke `daftar_jenis_kunjungan.id` (default atau lookup) |
|
||||
| - | `Jenis_pelayanan` | FK ke `daftar_jenis_pelayanan.id` (bisa dari `data_jenis_layanan.Jenis_pelayanan`) |
|
||||
| - | `Dokter` | FK ke `data_pegawai.id` (null jika belum ditentukan) |
|
||||
| - | `Jam_awal` | Jam mulai pelayanan (bisa dari `jamPanggil` atau null) |
|
||||
| - | `Jam_selesai` | Jam selesai pelayanan (null jika belum selesai) |
|
||||
| - | `Tanggal_ambil_hasil` | Tanggal ambil hasil (null jika belum) |
|
||||
| - | `Status_active` | Status aktif (default: 1 = Active) |
|
||||
|
||||
**Mapping Status:**
|
||||
- `status: "di-loket"` → `Status_kunjungan` = 1 (LOKET)
|
||||
- `status: "waiting"` → `Status_kunjungan` = 2 (PENDING) atau sesuai lookup
|
||||
- `processStage: "klinik"` → `Status_kunjungan` = 2 (KLINIK)
|
||||
- `processStage: "loket"` → `Status_kunjungan` = 1 (LOKET)
|
||||
|
||||
**Mapping FastTrack:**
|
||||
- `fastTrack: "YA"` → `Status_fasttrack` = 1 (True)
|
||||
- `fastTrack: "TIDAK"` → `Status_fasttrack` = 0 (False)
|
||||
|
||||
---
|
||||
|
||||
### 3. **data_kunjungan_tempat_panggilan** (Riwayat Panggilan)
|
||||
|
||||
| Field Code | Field ERD | Keterangan |
|
||||
|------------|-----------|------------|
|
||||
| `jamPanggil` | `Jam_panggilan` | Jam panggilan pasien (format: "HH:MM") |
|
||||
| `status` | `Status_panggilan` | FK ke lookup `ID: Status_panggilan` (harus mapping berdasarkan context) |
|
||||
| `processStage` | `Status_kunjungan` | FK ke lookup `ID: Status_kunjungan` |
|
||||
| - | `Nama_tempat_panggilan` | Nama tempat panggilan (bisa dari `loket` atau `klinik`) |
|
||||
| - | `FK_kunjungantempallayana` | FK ke `data_kunjungan_tempat_layanan.id` |
|
||||
| - | `Status_active` | Status aktif (default: 1 = Active) |
|
||||
|
||||
**Mapping Status Panggilan:**
|
||||
- Panggilan di Anjungan → `Status_panggilan` = 1 (ANJUNGAN)
|
||||
- Panggilan di Pendaftaran → `Status_panggilan` = 2 (PENDAFTARAN)
|
||||
- Panggilan di Pelayanan → `Status_panggilan` = 3 (PELAYANAN)
|
||||
- Panggilan ambil hasil → `Status_panggilan` = 4 (AMBIL HASIL)
|
||||
|
||||
---
|
||||
|
||||
### 4. **data_kunjungan_tempat_layanan_detail** (Detail Status Kunjungan)
|
||||
|
||||
| Field Code | Field ERD | Keterangan |
|
||||
|------------|-----------|------------|
|
||||
| `createdAt` | `Tanggal_detail` | Tanggal detail status (bisa dari `createdAt`) |
|
||||
| `status` | `Status_kunjungan` | FK ke lookup `ID: Status_kunjungan` |
|
||||
| - | `FK_kunjungantempallayana` | FK ke `data_kunjungan_tempat_layanan.id` |
|
||||
| - | `Status_active` | Status aktif (default: 1 = Active) |
|
||||
|
||||
**Catatan:** Tabel ini untuk tracking perubahan status kunjungan dari waktu ke waktu.
|
||||
|
||||
---
|
||||
|
||||
### 5. **data_pasien** (Data Pasien - Jika Belum Ada)
|
||||
|
||||
| Field Code | Field ERD | Keterangan |
|
||||
|------------|-----------|------------|
|
||||
| `barcode` | `Nomor_rekamedik` | Bisa digunakan sebagai nomor rekam medis sementara |
|
||||
| - | `Nama` | Nama pasien (harus diinput atau dari sistem lain) |
|
||||
| - | `Nomor_identitas` | NIK/KTP (harus diinput atau dari sistem lain) |
|
||||
| - | `Nomor_bpjs` | Nomor BPJS (jika `pembayaran` = "BPJS") |
|
||||
| - | `Status_antrean` | Status antrian pasien |
|
||||
| - | `Status_active` | Status aktif (default: 1 = Active) |
|
||||
|
||||
**Catatan:** Jika pasien belum ada di database, harus dibuat record baru di `data_pasien` terlebih dahulu.
|
||||
|
||||
---
|
||||
|
||||
### 6. **Lookup Tables yang Digunakan**
|
||||
|
||||
#### **ID: Status_fasttrack**
|
||||
- 0: False
|
||||
- 1: True
|
||||
|
||||
#### **ID: Status_kunjungan**
|
||||
- 1: LOKET
|
||||
- 2: KLINIK
|
||||
- 3: FARMASI
|
||||
- 4: PENUNJANG
|
||||
- 5: RAWAT INAP
|
||||
|
||||
**Atau (versi status):**
|
||||
- 1: ACTIVE
|
||||
- 2: PENDING
|
||||
- 3: TERLAMBAT
|
||||
- 4: KONSUL
|
||||
- 5: BATAL
|
||||
- 6: GAGAL
|
||||
- 7: AMBIL HASIL
|
||||
- 8: SELESAI PELAYANAN
|
||||
|
||||
#### **ID: Status_panggilan**
|
||||
- 1: ANJUNGAN
|
||||
- 2: PENDAFTARAN
|
||||
- 3: PELAYANAN
|
||||
- 4: AMBIL HASIL
|
||||
|
||||
#### **ID: Status_active**
|
||||
- 0: Disabled
|
||||
- 1: Active
|
||||
|
||||
---
|
||||
|
||||
## Alur Penyimpanan Data
|
||||
|
||||
### Step 1: Cek/Create Pasien
|
||||
1. Cari `data_pasien` berdasarkan `barcode` atau `Nomor_rekamedik`
|
||||
2. Jika tidak ada, buat record baru di `data_pasien`
|
||||
|
||||
### Step 2: Create Kunjungan Antrean
|
||||
1. Insert ke `data_kunjungan_antrean`:
|
||||
- `Barcode` = `barcode`
|
||||
- `Pasien` = `data_pasien.id` (dari step 1)
|
||||
- `Tanggal_daftar` = `createdAt`
|
||||
- `Status_active` = 1
|
||||
|
||||
### Step 3: Create Tempat Layanan
|
||||
1. Lookup `data_jenis_layanan.id` berdasarkan `klinik` (nama klinik)
|
||||
2. Lookup `daftar_penjamin.id` berdasarkan `pembayaran` ("BPJS" atau "UMUM")
|
||||
3. Lookup `data_loket.id` berdasarkan `loket` atau `loketId`
|
||||
4. Insert ke `data_kunjungan_tempat_layanan`:
|
||||
- `Nomor_tiket` = `no`
|
||||
- `FK_kunjunganantrean_ten` = `data_kunjungan_antrean.id` (dari step 2)
|
||||
- `Jenis_layanan` = `data_jenis_layanan.id`
|
||||
- `Penjamin` = `daftar_penjamin.id`
|
||||
- `Loket` = `data_loket.id`
|
||||
- `Status_fasttrack` = 1 jika `fastTrack` = "YA", else 0
|
||||
- `Status_kunjungan` = mapping dari `processStage` atau `status`
|
||||
- `Status_active` = 1
|
||||
|
||||
### Step 4: Create Panggilan (Jika Ada)
|
||||
1. Insert ke `data_kunjungan_tempat_panggilan`:
|
||||
- `FK_kunjungantempallayana` = `data_kunjungan_tempat_layanan.id` (dari step 3)
|
||||
- `Jam_panggilan` = `jamPanggil`
|
||||
- `Nama_tempat_panggilan` = `loket` atau `klinik`
|
||||
- `Status_panggilan` = mapping berdasarkan context
|
||||
- `Status_kunjungan` = mapping dari `processStage`
|
||||
- `Status_active` = 1
|
||||
|
||||
### Step 5: Create Detail Status (Optional)
|
||||
1. Insert ke `data_kunjungan_tempat_layanan_detail`:
|
||||
- `FK_kunjungantempallayana` = `data_kunjungan_tempat_layanan.id`
|
||||
- `Tanggal_detail` = `createdAt`
|
||||
- `Status_kunjungan` = mapping dari `status` atau `processStage`
|
||||
- `Status_active` = 1
|
||||
|
||||
---
|
||||
|
||||
## Field yang Tidak Langsung Map
|
||||
|
||||
### Field yang Perlu Lookup/Transform:
|
||||
1. **`klinik`** → Perlu lookup ke `data_jenis_layanan.id` berdasarkan nama
|
||||
2. **`pembayaran`** → Perlu lookup ke `daftar_penjamin.id` berdasarkan value ("BPJS" atau "UMUM")
|
||||
3. **`loket`** → Perlu lookup ke `data_loket.id` berdasarkan nama loket
|
||||
4. **`shift`** → Perlu lookup ke `data_jenis_layanan_shift.id` berdasarkan shift dan jadwal
|
||||
5. **`status`** → Perlu mapping ke lookup `ID: Status_kunjungan`
|
||||
6. **`processStage`** → Perlu mapping ke lookup `ID: Status_kunjungan`
|
||||
7. **`fastTrack`** → Perlu mapping ke lookup `ID: Status_fasttrack` (0 atau 1)
|
||||
|
||||
### Field yang Hanya untuk Display/Reference:
|
||||
1. **`noAntrian`** → Format display, bisa di-generate ulang dari `Nomor_tiket` dan `Barcode`
|
||||
2. **`referencePatient`** → Reference ke kunjungan sebelumnya (relasi ke `data_kunjungan_antrean` lain)
|
||||
|
||||
---
|
||||
|
||||
## Contoh Mapping Lengkap
|
||||
|
||||
### Input Data:
|
||||
```javascript
|
||||
{
|
||||
no: 1,
|
||||
jamPanggil: "12:49",
|
||||
barcode: "26011395625",
|
||||
noAntrian: "UM1001 | Online - 26011395625",
|
||||
shift: "Shift 1",
|
||||
klinik: "KANDUNGAN",
|
||||
fastTrack: "YA",
|
||||
pembayaran: "BPJS",
|
||||
status: "di-loket",
|
||||
processStage: "loket",
|
||||
createdAt: "2026-01-13T16:51:35.502Z",
|
||||
loket: "Loket A",
|
||||
loketId: 1
|
||||
}
|
||||
```
|
||||
|
||||
### Output ke Database:
|
||||
|
||||
#### data_kunjungan_antrean:
|
||||
```sql
|
||||
INSERT INTO data_kunjungan_antrean (
|
||||
Barcode,
|
||||
Pasien,
|
||||
Tanggal_daftar,
|
||||
Status_active
|
||||
) VALUES (
|
||||
'26011395625',
|
||||
[data_pasien.id], -- dari lookup
|
||||
'2026-01-13T16:51:35.502Z',
|
||||
1
|
||||
);
|
||||
```
|
||||
|
||||
#### data_kunjungan_tempat_layanan:
|
||||
```sql
|
||||
INSERT INTO data_kunjungan_tempat_layanan (
|
||||
Nomor_tiket,
|
||||
FK_kunjunganantrean_ten,
|
||||
Penjamin, -- lookup dari "BPJS"
|
||||
Jenis_layanan, -- lookup dari "KANDUNGAN"
|
||||
Loket, -- lookup dari "Loket A" atau langsung 1
|
||||
Status_fasttrack, -- 1 (karena "YA")
|
||||
Status_kunjungan, -- 1 (karena "loket" → LOKET)
|
||||
Status_active
|
||||
) VALUES (
|
||||
1,
|
||||
[data_kunjungan_antrean.id],
|
||||
[daftar_penjamin.id WHERE Penjamin = 'BPJS'],
|
||||
[data_jenis_layanan.id WHERE Nama_jenis_layanan = 'KANDUNGAN'],
|
||||
1,
|
||||
1,
|
||||
1,
|
||||
1
|
||||
);
|
||||
```
|
||||
|
||||
#### data_kunjungan_tempat_panggilan:
|
||||
```sql
|
||||
INSERT INTO data_kunjungan_tempat_panggilan (
|
||||
FK_kunjungantempallayana,
|
||||
Jam_panggilan,
|
||||
Nama_tempat_panggilan,
|
||||
Status_panggilan, -- 2 (PENDAFTARAN) atau sesuai context
|
||||
Status_kunjungan, -- 1 (LOKET)
|
||||
Status_active
|
||||
) VALUES (
|
||||
[data_kunjungan_tempat_layanan.id],
|
||||
'12:49',
|
||||
'Loket A',
|
||||
2, -- PENDAFTARAN
|
||||
1, -- LOKET
|
||||
1
|
||||
);
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Catatan Penting
|
||||
|
||||
1. **Foreign Key Lookups**: Banyak field yang memerlukan lookup ke tabel lain sebelum insert
|
||||
2. **Status Mapping**: Field `status` dan `processStage` perlu mapping ke lookup table `ID: Status_kunjungan`
|
||||
3. **Default Values**: Field yang tidak ada di code perlu diisi dengan default value atau null
|
||||
4. **Relasi**: `referencePatient` bisa digunakan untuk membuat relasi ke `data_kunjungan_antrean` sebelumnya
|
||||
5. **Shift**: Field `shift` perlu diambil dari `data_jenis_layanan_shift` berdasarkan jadwal dan jenis layanan
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -506,6 +506,78 @@
|
||||
</v-card>
|
||||
</v-dialog>
|
||||
|
||||
<!-- Fast Track Dialog -->
|
||||
<v-dialog
|
||||
v-model="showFastTrackDialog"
|
||||
max-width="600"
|
||||
persistent
|
||||
@click:outside="showFastTrackDialog = false"
|
||||
>
|
||||
<v-card class="dialog-card">
|
||||
<v-card-title class="dialog-header">
|
||||
<v-icon class="mr-2">mdi-fast-forward</v-icon>
|
||||
Formulir Fast Track
|
||||
</v-card-title>
|
||||
<v-divider />
|
||||
<v-card-text class="pa-6">
|
||||
<v-form>
|
||||
<v-text-field
|
||||
v-model="fastTrackForm.penanggungJawab"
|
||||
label="Penanggung Jawab"
|
||||
variant="outlined"
|
||||
density="compact"
|
||||
required
|
||||
class="mb-3"
|
||||
:rules="[v => !!v || 'Mohon isi Penanggung Jawab']"
|
||||
/>
|
||||
|
||||
<v-textarea
|
||||
v-model="fastTrackForm.alasanFastTrack"
|
||||
label="Alasan Fast Track"
|
||||
variant="outlined"
|
||||
density="compact"
|
||||
required
|
||||
rows="3"
|
||||
class="mb-3"
|
||||
:rules="[v => !!v || 'Mohon isi Alasan Fast Track']"
|
||||
/>
|
||||
|
||||
<!-- Jenis Pembayaran hanya untuk non-Eksekutif -->
|
||||
<v-select
|
||||
v-if="!isEksekutif"
|
||||
v-model="fastTrackForm.jenisPembayaran"
|
||||
:items="['BPJS', 'UMUM']"
|
||||
label="Jenis Pembayaran"
|
||||
variant="outlined"
|
||||
density="compact"
|
||||
required
|
||||
class="mb-3"
|
||||
:rules="[v => !!v || 'Mohon pilih Jenis Pembayaran']"
|
||||
/>
|
||||
</v-form>
|
||||
</v-card-text>
|
||||
<v-divider />
|
||||
<v-card-actions class="pa-4">
|
||||
<v-spacer />
|
||||
<v-btn
|
||||
variant="outlined"
|
||||
color="neutral-600"
|
||||
@click="showFastTrackDialog = false"
|
||||
>
|
||||
Batal
|
||||
</v-btn>
|
||||
<v-btn
|
||||
color="success-600"
|
||||
class="text-white"
|
||||
variant="flat"
|
||||
@click="submitFastTrackForm"
|
||||
>
|
||||
Lanjutkan
|
||||
</v-btn>
|
||||
</v-card-actions>
|
||||
</v-card>
|
||||
</v-dialog>
|
||||
|
||||
<!-- Print Dialog -->
|
||||
<v-dialog
|
||||
v-model="showPrintDialog"
|
||||
@@ -918,6 +990,7 @@ const showVisitTypeDialog = ref(false);
|
||||
const showBookingFormDialog = ref(false);
|
||||
const showDoctorSelectionDialog = ref(false);
|
||||
const showPrintDialog = ref(false);
|
||||
const showFastTrackDialog = ref(false);
|
||||
const lastRegisteredPatient = ref(null);
|
||||
const selectedClinic = ref(null);
|
||||
const selectedDoctor = ref(null);
|
||||
@@ -925,6 +998,13 @@ const snackbar = ref(false);
|
||||
const snackbarText = ref("");
|
||||
const snackbarColor = ref("success");
|
||||
|
||||
// Fast Track form data
|
||||
const fastTrackForm = ref({
|
||||
penanggungJawab: "",
|
||||
alasanFastTrack: "",
|
||||
jenisPembayaran: "UMUM", // Default untuk non-Eksekutif
|
||||
});
|
||||
|
||||
const bookingForm = ref({
|
||||
date: new Date().toISOString().substring(0, 10),
|
||||
shift: "Shift 1",
|
||||
@@ -1063,15 +1143,24 @@ const registerPatientDirectly = async (paymentType) => {
|
||||
|
||||
showVisitTypeDialog.value = false;
|
||||
|
||||
// Untuk pasien Eksekutif, dokter sudah dipilih di dialog sebelumnya
|
||||
// Untuk Reguler/BPJS, tidak perlu dokter
|
||||
const namaDokter = isEksekutif.value ? selectedDoctor.value : null;
|
||||
|
||||
// Handle Fast Track - paymentType akan menjadi 'UMUM' atau 'BPJS' tapi dengan flag fastTrack
|
||||
// Handle Fast Track - tampilkan dialog Fast Track sebelum registrasi
|
||||
const isFastTrack = paymentType === 'FAST_TRACK';
|
||||
const actualPaymentType = isFastTrack ? 'UMUM' : paymentType;
|
||||
|
||||
await registerPatient('SEKARANG', actualPaymentType, namaDokter, isFastTrack);
|
||||
if (isFastTrack) {
|
||||
// Reset form Fast Track
|
||||
fastTrackForm.value = {
|
||||
penanggungJawab: "",
|
||||
alasanFastTrack: "",
|
||||
jenisPembayaran: "UMUM", // Default untuk non-Eksekutif
|
||||
};
|
||||
// Tampilkan dialog Fast Track
|
||||
showFastTrackDialog.value = true;
|
||||
} else {
|
||||
// Untuk pasien Eksekutif, dokter sudah dipilih di dialog sebelumnya
|
||||
// Untuk Reguler/BPJS, tidak perlu dokter
|
||||
const namaDokter = isEksekutif.value ? selectedDoctor.value : null;
|
||||
await registerPatient('SEKARANG', paymentType, namaDokter, false);
|
||||
}
|
||||
};
|
||||
|
||||
// Fungsi ini tidak lagi digunakan karena dokter dipilih di dialog konfirmasi
|
||||
@@ -1089,12 +1178,12 @@ const confirmDoctorSelection = () => {
|
||||
registerPatient('SEKARANG', 'Eksekutif', selectedDoctor.value);
|
||||
};
|
||||
|
||||
const registerPatient = async (visitType, paymentType, namaDokter, isFastTrack = false) => {
|
||||
const registerPatient = async (visitType, paymentType, namaDokter, isFastTrack = false, fastTrackData = null) => {
|
||||
try {
|
||||
// Validasi bahwa fungsi registerPatientFromAnjungan ada
|
||||
if (!queueStore) {
|
||||
console.error('❌ queueStore is not initialized');
|
||||
showSnackbar('Error', 'Store tidak ter-initialize. Silakan refresh halaman.', 'error');
|
||||
showSnackbar('Store tidak ter-initialize. Silakan refresh halaman.', 'error');
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1102,7 +1191,7 @@ const registerPatient = async (visitType, paymentType, namaDokter, isFastTrack =
|
||||
console.error('❌ queueStore.registerPatientFromAnjungan is not a function');
|
||||
console.error('queueStore:', queueStore);
|
||||
console.error('Available methods:', Object.keys(queueStore || {}));
|
||||
showSnackbar('Error', 'Fungsi registrasi tidak tersedia. Silakan refresh halaman.', 'error');
|
||||
showSnackbar('Fungsi registrasi tidak tersedia. Silakan refresh halaman.', 'error');
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1114,7 +1203,8 @@ const registerPatient = async (visitType, paymentType, namaDokter, isFastTrack =
|
||||
null,
|
||||
'Shift 1',
|
||||
namaDokter,
|
||||
isFastTrack
|
||||
isFastTrack,
|
||||
fastTrackData // Pass fastTrackData (penanggungJawab, alasanFastTrack)
|
||||
);
|
||||
|
||||
if (result && result.success && result.patient) {
|
||||
@@ -1170,7 +1260,7 @@ const submitBooking = async () => {
|
||||
// Validasi bahwa fungsi registerPatientFromAnjungan ada
|
||||
if (!queueStore) {
|
||||
console.error('❌ queueStore is not initialized');
|
||||
showSnackbar('Error', 'Store tidak ter-initialize. Silakan refresh halaman.', 'error');
|
||||
showSnackbar('Store tidak ter-initialize. Silakan refresh halaman.', 'error');
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1178,7 +1268,7 @@ const submitBooking = async () => {
|
||||
console.error('❌ queueStore.registerPatientFromAnjungan is not a function');
|
||||
console.error('queueStore:', queueStore);
|
||||
console.error('Available methods:', Object.keys(queueStore || {}));
|
||||
showSnackbar('Error', 'Fungsi registrasi tidak tersedia. Silakan refresh halaman.', 'error');
|
||||
showSnackbar('Fungsi registrasi tidak tersedia. Silakan refresh halaman.', 'error');
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1237,6 +1327,45 @@ const skipPrint = () => {
|
||||
lastRegisteredPatient.value = null;
|
||||
};
|
||||
|
||||
// Handle Fast Track dialog submission
|
||||
const submitFastTrackForm = async () => {
|
||||
// Validasi form
|
||||
if (!fastTrackForm.value.penanggungJawab.trim()) {
|
||||
showSnackbar("Mohon isi Penanggung Jawab", "error");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!fastTrackForm.value.alasanFastTrack.trim()) {
|
||||
showSnackbar("Mohon isi Alasan Fast Track", "error");
|
||||
return;
|
||||
}
|
||||
|
||||
// Untuk non-Eksekutif, validasi jenis pembayaran
|
||||
if (!isEksekutif.value && !fastTrackForm.value.jenisPembayaran) {
|
||||
showSnackbar("Mohon pilih Jenis Pembayaran", "error");
|
||||
return;
|
||||
}
|
||||
|
||||
// Tutup dialog Fast Track
|
||||
showFastTrackDialog.value = false;
|
||||
|
||||
// Untuk pasien Eksekutif, dokter sudah dipilih di dialog sebelumnya
|
||||
// Untuk Reguler/BPJS, tidak perlu dokter
|
||||
const namaDokter = isEksekutif.value ? selectedDoctor.value : null;
|
||||
|
||||
// Tentukan paymentType berdasarkan jenis pasien
|
||||
const paymentType = isEksekutif.value ? 'Eksekutif' : fastTrackForm.value.jenisPembayaran;
|
||||
|
||||
// Siapkan data Fast Track
|
||||
const fastTrackData = {
|
||||
penanggungJawab: fastTrackForm.value.penanggungJawab.trim(),
|
||||
alasanFastTrack: fastTrackForm.value.alasanFastTrack.trim(),
|
||||
};
|
||||
|
||||
// Register dengan Fast Track
|
||||
await registerPatient('SEKARANG', paymentType, namaDokter, true, fastTrackData);
|
||||
};
|
||||
|
||||
const backToList = () => {
|
||||
navigateTo("/anjungan/anjungan");
|
||||
};
|
||||
@@ -1628,6 +1757,7 @@ watch(lastRegisteredPatient, (newVal) => {
|
||||
word-wrap: break-word;
|
||||
display: -webkit-box;
|
||||
-webkit-line-clamp: 2;
|
||||
line-clamp: 2;
|
||||
-webkit-box-orient: vertical;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
@@ -1755,6 +1885,7 @@ watch(lastRegisteredPatient, (newVal) => {
|
||||
line-height: 1.3;
|
||||
display: -webkit-box;
|
||||
-webkit-line-clamp: 3;
|
||||
line-clamp: 3;
|
||||
-webkit-box-orient: vertical;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
|
||||
@@ -2154,9 +2154,11 @@ const extractQRData = (qrData: string): { barcode: string; status?: string } =>
|
||||
|
||||
// Helper function untuk extract kode dan angka dari noAntrian
|
||||
// Contoh: "UM0014 | Onsite - ..." -> { kode: "UM", angka: "0014" }
|
||||
// Contoh: "F-RA001 | Onsite - ..." -> { kode: "RA", angka: "001" } (handle "F-" prefix)
|
||||
const extractKodeAndAngka = (noAntrian: string): { kode: string; angka: string } | null => {
|
||||
if (!noAntrian) return null;
|
||||
const match = noAntrian.toUpperCase().match(/^([A-Z]+)(\d+)/);
|
||||
// Handle format "F-RA001" by matching after "F-" prefix if exists
|
||||
const match = noAntrian.toUpperCase().match(/^(?:F-)?([A-Z]+)(\d+)/);
|
||||
if (match) {
|
||||
return { kode: match[1], angka: match[2] };
|
||||
}
|
||||
@@ -2165,20 +2167,26 @@ const extractKodeAndAngka = (noAntrian: string): { kode: string; angka: string }
|
||||
|
||||
// Helper function untuk membandingkan input dengan noAntrian (kode + angka harus match)
|
||||
// Ini mencegah false positive ketika angka sama tapi kode beda (misalnya UM0014 vs AN0014)
|
||||
// Handle format "F-RA001" dengan menghapus prefix "F-" untuk comparison
|
||||
const matchNoAntrian = (input: string, noAntrian: string): boolean => {
|
||||
if (!input || !noAntrian) return false;
|
||||
|
||||
const cleanInput = String(input).trim().toUpperCase();
|
||||
const noAntrianUpper = String(noAntrian).toUpperCase();
|
||||
|
||||
// 1. Extract kode + angka dari noAntrian (misalnya "UM0014 | ..." -> kode: "UM", angka: "0014")
|
||||
// Remove "F-" prefix from both input and noAntrian for comparison
|
||||
const cleanInputWithoutPrefix = cleanInput.replace(/^F-/, '');
|
||||
const noAntrianWithoutPrefix = noAntrianUpper.replace(/^F-/, '');
|
||||
|
||||
// 1. Extract kode + angka dari noAntrian (misalnya "F-RA001 | ..." -> kode: "RA", angka: "001")
|
||||
const noAntrianParts = extractKodeAndAngka(noAntrian);
|
||||
if (!noAntrianParts) {
|
||||
// Jika noAntrian tidak punya format kode+angka, gunakan exact match saja
|
||||
return noAntrianUpper === cleanInput;
|
||||
// Check both with and without prefix
|
||||
return noAntrianUpper === cleanInput || noAntrianWithoutPrefix === cleanInputWithoutPrefix;
|
||||
}
|
||||
|
||||
// 2. Extract kode + angka dari input (misalnya "AN002" -> kode: "AN", angka: "002")
|
||||
// 2. Extract kode + angka dari input (misalnya "F-RA001" atau "RA001" -> kode: "RA", angka: "001")
|
||||
const inputParts = extractKodeAndAngka(cleanInput);
|
||||
|
||||
// 3. Jika input punya kode + angka, HARUS match kode dan angka
|
||||
@@ -2195,33 +2203,40 @@ const matchNoAntrian = (input: string, noAntrian: string): boolean => {
|
||||
|
||||
// 4. Jika input hanya angka (tidak punya kode), JANGAN match
|
||||
// Ini mencegah match "002" dengan "UM1002" atau "AN002" dengan "UM1002"
|
||||
const inputAngka = cleanInput.replace(/[^0-9]/g, '');
|
||||
if (inputAngka && inputAngka === cleanInput) {
|
||||
const inputAngka = cleanInputWithoutPrefix.replace(/[^0-9]/g, '');
|
||||
if (inputAngka && inputAngka === cleanInputWithoutPrefix) {
|
||||
// Input hanya angka, tidak match karena tidak ada kode
|
||||
return false;
|
||||
}
|
||||
|
||||
// 5. Exact match untuk kasus lain (jika input mengandung kode tapi tidak ter-extract)
|
||||
// Hanya exact match, tidak menggunakan startsWith atau includes untuk menghindari false positive
|
||||
if (noAntrianUpper === cleanInput) {
|
||||
// Check both with and without prefix
|
||||
if (noAntrianUpper === cleanInput || noAntrianWithoutPrefix === cleanInputWithoutPrefix) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// 6. Check jika noAntrian dimulai dengan input + spasi atau pipe (untuk partial match yang aman)
|
||||
// Contoh: "AN002" match dengan "AN002 | ..." atau "AN002 | Onsite - ..."
|
||||
// Contoh: "F-RA001" match dengan "F-RA001 | ..." atau "RA001" match dengan "F-RA001 | ..."
|
||||
// Tapi TIDAK match dengan "UM1002" karena kode berbeda
|
||||
if (noAntrianParts && inputParts) {
|
||||
// Jika kedua-duanya punya kode+angka, hanya match jika kode sama
|
||||
if (inputParts.kode === noAntrianParts.kode) {
|
||||
// Check jika noAntrian dimulai dengan format "KODEANGKA |" atau "KODEANGKA | ..."
|
||||
// Check jika noAntrian dimulai dengan format "F-KODEANGKA |" atau "KODEANGKA | ..."
|
||||
const noAntrianPrefix = `${noAntrianParts.kode}${noAntrianParts.angka}`;
|
||||
const inputPrefix = `${inputParts.kode}${inputParts.angka}`;
|
||||
|
||||
// Pastikan input prefix sama dengan noAntrian prefix
|
||||
if (inputPrefix === noAntrianPrefix) {
|
||||
// Check jika noAntrian dimulai dengan prefix ini diikuti spasi, pipe, atau end of string
|
||||
if (noAntrianUpper.startsWith(noAntrianPrefix)) {
|
||||
const nextChar = noAntrianUpper[noAntrianPrefix.length];
|
||||
// Check jika noAntrian dimulai dengan prefix ini (with or without "F-") diikuti spasi, pipe, atau end of string
|
||||
if (noAntrianWithoutPrefix.startsWith(noAntrianPrefix)) {
|
||||
const nextChar = noAntrianWithoutPrefix[noAntrianPrefix.length];
|
||||
if (!nextChar || nextChar === ' ' || nextChar === '|') {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
// Also check with "F-" prefix
|
||||
if (noAntrianUpper.startsWith(`F-${noAntrianPrefix}`)) {
|
||||
const nextChar = noAntrianUpper[`F-${noAntrianPrefix}`.length];
|
||||
if (!nextChar || nextChar === ' ' || nextChar === '|') {
|
||||
return true;
|
||||
}
|
||||
|
||||
+386
-36
@@ -113,13 +113,18 @@ export const useQueueStore = defineStore('queue', () => {
|
||||
const seedBarcode10 = generateBarcode(seedBarcodes); seedBarcodes.push(seedBarcode10);
|
||||
const seedBarcode11 = generateBarcode(seedBarcodes); seedBarcodes.push(seedBarcode11);
|
||||
const seedBarcode12 = generateBarcode(seedBarcodes); seedBarcodes.push(seedBarcode12);
|
||||
// Barcode untuk pasien Eksekutif
|
||||
const seedBarcodeE1 = generateBarcode(seedBarcodes); seedBarcodes.push(seedBarcodeE1);
|
||||
const seedBarcodeE2 = generateBarcode(seedBarcodes); seedBarcodes.push(seedBarcodeE2);
|
||||
const seedBarcodeE3 = generateBarcode(seedBarcodes); seedBarcodes.push(seedBarcodeE3);
|
||||
const seedBarcodeE4 = generateBarcode(seedBarcodes); seedBarcodes.push(seedBarcodeE4);
|
||||
|
||||
const seedPatients = [
|
||||
{
|
||||
no: 1,
|
||||
jamPanggil: "12:49",
|
||||
barcode: seedBarcode1, // Barcode unik untuk setiap pasien
|
||||
noAntrian: `UM1001 | Online - ${seedBarcode1}`,
|
||||
noAntrian: `F-RA001 | Online - ${seedBarcode1}`, // Counter 1: Fast Track BPJS
|
||||
shift: "Shift 1",
|
||||
klinik: "KANDUNGAN",
|
||||
fastTrack: "YA", // Fast Track Patient
|
||||
@@ -127,12 +132,18 @@ export const useQueueStore = defineStore('queue', () => {
|
||||
status: "waiting",
|
||||
processStage: "loket",
|
||||
createdAt: new Date().toISOString(),
|
||||
registrationType: 'online',
|
||||
visitType: 'SEKARANG',
|
||||
visitDate: new Date().toISOString().substring(0, 10),
|
||||
namaDokter: null,
|
||||
penanggungJawab: "Dr. Ahmad Wijaya", // Fast Track data
|
||||
alasanFastTrack: "Pasien prioritas", // Fast Track data
|
||||
},
|
||||
{
|
||||
no: 2,
|
||||
jamPanggil: "10:52",
|
||||
barcode: seedBarcode2,
|
||||
noAntrian: `UM1002 | Online - ${seedBarcode2}`,
|
||||
noAntrian: `RA002 | Online - ${seedBarcode2}`, // Counter 2: Non-fast track UMUM
|
||||
shift: "Shift 1",
|
||||
klinik: "IPD",
|
||||
fastTrack: "TIDAK",
|
||||
@@ -140,12 +151,18 @@ export const useQueueStore = defineStore('queue', () => {
|
||||
status: "waiting",
|
||||
processStage: "loket",
|
||||
createdAt: new Date().toISOString(),
|
||||
registrationType: 'online',
|
||||
visitType: 'SEKARANG',
|
||||
visitDate: new Date().toISOString().substring(0, 10),
|
||||
namaDokter: null,
|
||||
penanggungJawab: null,
|
||||
alasanFastTrack: null,
|
||||
},
|
||||
{
|
||||
no: 3,
|
||||
jamPanggil: "09:30",
|
||||
barcode: seedBarcode3,
|
||||
noAntrian: `UM1003 | Online - ${seedBarcode3}`,
|
||||
noAntrian: `F-RA003 | Online - ${seedBarcode3}`, // Counter 3: Fast Track BPJS
|
||||
shift: "Shift 1",
|
||||
klinik: "SARAF",
|
||||
fastTrack: "YA", // Fast Track Patient
|
||||
@@ -153,12 +170,18 @@ export const useQueueStore = defineStore('queue', () => {
|
||||
status: "waiting",
|
||||
processStage: "loket",
|
||||
createdAt: new Date().toISOString(),
|
||||
registrationType: 'online',
|
||||
visitType: 'SEKARANG',
|
||||
visitDate: new Date().toISOString().substring(0, 10),
|
||||
namaDokter: null,
|
||||
penanggungJawab: "Dr. Budi Santoso", // Fast Track data
|
||||
alasanFastTrack: "Kondisi darurat", // Fast Track data
|
||||
},
|
||||
{
|
||||
no: 4,
|
||||
jamPanggil: "14:15",
|
||||
barcode: seedBarcode4,
|
||||
noAntrian: `UM1004 | Online - ${seedBarcode4}`,
|
||||
noAntrian: `RA004 | Online - ${seedBarcode4}`, // Counter 4: Non-fast track UMUM
|
||||
shift: "Shift 1",
|
||||
klinik: "THT",
|
||||
fastTrack: "TIDAK",
|
||||
@@ -166,12 +189,18 @@ export const useQueueStore = defineStore('queue', () => {
|
||||
status: "waiting",
|
||||
processStage: "loket",
|
||||
createdAt: new Date().toISOString(),
|
||||
registrationType: 'online',
|
||||
visitType: 'SEKARANG',
|
||||
visitDate: new Date().toISOString().substring(0, 10),
|
||||
namaDokter: null,
|
||||
penanggungJawab: null,
|
||||
alasanFastTrack: null,
|
||||
},
|
||||
{
|
||||
no: 5,
|
||||
jamPanggil: "12:49",
|
||||
barcode: seedBarcode5,
|
||||
noAntrian: `UM1005 | Online - ${seedBarcode5}`,
|
||||
noAntrian: `RA005 | Online - ${seedBarcode5}`, // Counter 5: Non-fast track UMUM
|
||||
shift: "Shift 2",
|
||||
klinik: "KANDUNGAN",
|
||||
fastTrack: "TIDAK",
|
||||
@@ -179,12 +208,18 @@ export const useQueueStore = defineStore('queue', () => {
|
||||
status: "waiting",
|
||||
processStage: "loket",
|
||||
createdAt: new Date().toISOString(),
|
||||
registrationType: 'online',
|
||||
visitType: 'SEKARANG',
|
||||
visitDate: new Date().toISOString().substring(0, 10),
|
||||
namaDokter: null,
|
||||
penanggungJawab: null,
|
||||
alasanFastTrack: null,
|
||||
},
|
||||
{
|
||||
no: 6,
|
||||
jamPanggil: "10:52",
|
||||
barcode: seedBarcode6,
|
||||
noAntrian: `UM1006 | Online - ${seedBarcode6}`,
|
||||
noAntrian: `F-RA006 | Online - ${seedBarcode6}`, // Counter 6: Fast Track BPJS
|
||||
shift: "Shift 1",
|
||||
klinik: "IPD",
|
||||
fastTrack: "YA", // Fast Track Patient
|
||||
@@ -192,12 +227,18 @@ export const useQueueStore = defineStore('queue', () => {
|
||||
status: "waiting",
|
||||
processStage: "loket",
|
||||
createdAt: new Date().toISOString(),
|
||||
registrationType: 'online',
|
||||
visitType: 'SEKARANG',
|
||||
visitDate: new Date().toISOString().substring(0, 10),
|
||||
namaDokter: null,
|
||||
penanggungJawab: "Dr. Citra Dewi", // Fast Track data
|
||||
alasanFastTrack: "Rujukan darurat", // Fast Track data
|
||||
},
|
||||
{
|
||||
no: 7,
|
||||
jamPanggil: "09:30",
|
||||
barcode: seedBarcode7,
|
||||
noAntrian: `UM1007 | Online - ${seedBarcode7}`,
|
||||
noAntrian: `RA007 | Online - ${seedBarcode7}`, // Counter 7: Non-fast track UMUM
|
||||
shift: "Shift 1",
|
||||
klinik: "SARAF",
|
||||
fastTrack: "TIDAK",
|
||||
@@ -205,12 +246,18 @@ export const useQueueStore = defineStore('queue', () => {
|
||||
status: "waiting",
|
||||
processStage: "loket",
|
||||
createdAt: new Date().toISOString(),
|
||||
registrationType: 'online',
|
||||
visitType: 'SEKARANG',
|
||||
visitDate: new Date().toISOString().substring(0, 10),
|
||||
namaDokter: null,
|
||||
penanggungJawab: null,
|
||||
alasanFastTrack: null,
|
||||
},
|
||||
{
|
||||
no: 8,
|
||||
jamPanggil: "14:15",
|
||||
barcode: seedBarcode8,
|
||||
noAntrian: `UM1008 | Online - ${seedBarcode8}`,
|
||||
noAntrian: `RA008 | Online - ${seedBarcode8}`, // Counter 8: Non-fast track UMUM
|
||||
shift: "Shift 1",
|
||||
klinik: "THT",
|
||||
fastTrack: "TIDAK",
|
||||
@@ -218,12 +265,18 @@ export const useQueueStore = defineStore('queue', () => {
|
||||
status: "waiting",
|
||||
processStage: "loket",
|
||||
createdAt: new Date().toISOString(),
|
||||
registrationType: 'online',
|
||||
visitType: 'SEKARANG',
|
||||
visitDate: new Date().toISOString().substring(0, 10),
|
||||
namaDokter: null,
|
||||
penanggungJawab: null,
|
||||
alasanFastTrack: null,
|
||||
},
|
||||
{
|
||||
no: 9,
|
||||
jamPanggil: "12:49",
|
||||
barcode: seedBarcode9,
|
||||
noAntrian: `UM1009 | Online - ${seedBarcode9}`,
|
||||
noAntrian: `F-RA009 | Online - ${seedBarcode9}`, // Counter 9: Fast Track BPJS
|
||||
shift: "Shift 2",
|
||||
klinik: "KANDUNGAN",
|
||||
fastTrack: "YA", // Fast Track Patient
|
||||
@@ -231,12 +284,18 @@ export const useQueueStore = defineStore('queue', () => {
|
||||
status: "waiting",
|
||||
processStage: "loket",
|
||||
createdAt: new Date().toISOString(),
|
||||
registrationType: 'online',
|
||||
visitType: 'SEKARANG',
|
||||
visitDate: new Date().toISOString().substring(0, 10),
|
||||
namaDokter: null,
|
||||
penanggungJawab: "Dr. Dedi Kurniawan", // Fast Track data
|
||||
alasanFastTrack: "Pasien VIP", // Fast Track data
|
||||
},
|
||||
{
|
||||
no: 10,
|
||||
jamPanggil: "10:52",
|
||||
barcode: seedBarcode10,
|
||||
noAntrian: `UM1010 | Online - ${seedBarcode10}`,
|
||||
noAntrian: `RA010 | Online - ${seedBarcode10}`, // Counter 10: Non-fast track UMUM
|
||||
shift: "Shift 1",
|
||||
klinik: "IPD",
|
||||
fastTrack: "TIDAK",
|
||||
@@ -244,12 +303,18 @@ export const useQueueStore = defineStore('queue', () => {
|
||||
status: "waiting",
|
||||
processStage: "loket",
|
||||
createdAt: new Date().toISOString(),
|
||||
registrationType: 'online',
|
||||
visitType: 'SEKARANG',
|
||||
visitDate: new Date().toISOString().substring(0, 10),
|
||||
namaDokter: null,
|
||||
penanggungJawab: null,
|
||||
alasanFastTrack: null,
|
||||
},
|
||||
{
|
||||
no: 11,
|
||||
jamPanggil: "09:30",
|
||||
barcode: seedBarcode11,
|
||||
noAntrian: `UM1011 | Online - ${seedBarcode11}`,
|
||||
noAntrian: `RA011 | Online - ${seedBarcode11}`, // Counter 11: Non-fast track UMUM
|
||||
shift: "Shift 1",
|
||||
klinik: "SARAF",
|
||||
fastTrack: "TIDAK",
|
||||
@@ -257,12 +322,18 @@ export const useQueueStore = defineStore('queue', () => {
|
||||
status: "waiting",
|
||||
processStage: "loket",
|
||||
createdAt: new Date().toISOString(),
|
||||
registrationType: 'online',
|
||||
visitType: 'SEKARANG',
|
||||
visitDate: new Date().toISOString().substring(0, 10),
|
||||
namaDokter: null,
|
||||
penanggungJawab: null,
|
||||
alasanFastTrack: null,
|
||||
},
|
||||
{
|
||||
no: 12,
|
||||
jamPanggil: "14:15",
|
||||
barcode: seedBarcode12,
|
||||
noAntrian: `UM1012 | Online - ${seedBarcode12}`,
|
||||
noAntrian: `F-RA012 | Online - ${seedBarcode12}`, // Counter 12: Fast Track BPJS
|
||||
shift: "Shift 2",
|
||||
klinik: "THT",
|
||||
fastTrack: "YA", // Fast Track Patient
|
||||
@@ -270,11 +341,138 @@ export const useQueueStore = defineStore('queue', () => {
|
||||
status: "waiting",
|
||||
processStage: "loket",
|
||||
createdAt: new Date().toISOString(),
|
||||
registrationType: 'online',
|
||||
visitType: 'SEKARANG',
|
||||
visitDate: new Date().toISOString().substring(0, 10),
|
||||
namaDokter: null,
|
||||
penanggungJawab: "Dr. Eka Putri", // Fast Track data
|
||||
alasanFastTrack: "Kondisi kritis", // Fast Track data
|
||||
},
|
||||
{
|
||||
no: 13,
|
||||
jamPanggil: "11:20",
|
||||
barcode: seedBarcodeE1, // Barcode unik untuk pasien Eksekutif
|
||||
noAntrian: `EA013 | Online - ${seedBarcodeE1}`, // Counter 13: Non-fast track Eksekutif
|
||||
shift: "Shift 1",
|
||||
klinik: "KANDUNGAN",
|
||||
fastTrack: "TIDAK",
|
||||
pembayaran: "Eksekutif",
|
||||
status: "waiting",
|
||||
processStage: "loket",
|
||||
createdAt: new Date().toISOString(),
|
||||
registrationType: 'online',
|
||||
visitType: 'SEKARANG',
|
||||
visitDate: new Date().toISOString().substring(0, 10),
|
||||
namaDokter: "Dr. Ahmad Wijaya, Sp.OG",
|
||||
penanggungJawab: null,
|
||||
alasanFastTrack: null,
|
||||
},
|
||||
{
|
||||
no: 14,
|
||||
jamPanggil: "13:45",
|
||||
barcode: seedBarcodeE2,
|
||||
noAntrian: `EA014 | Online - ${seedBarcodeE2}`, // Counter 14: Non-fast track Eksekutif
|
||||
shift: "Shift 1",
|
||||
klinik: "IPD",
|
||||
fastTrack: "TIDAK",
|
||||
pembayaran: "Eksekutif",
|
||||
status: "waiting",
|
||||
processStage: "loket",
|
||||
createdAt: new Date().toISOString(),
|
||||
registrationType: 'online',
|
||||
visitType: 'SEKARANG',
|
||||
visitDate: new Date().toISOString().substring(0, 10),
|
||||
namaDokter: "Dr. Budi Santoso, Sp.PD",
|
||||
penanggungJawab: null,
|
||||
alasanFastTrack: null,
|
||||
},
|
||||
{
|
||||
no: 15,
|
||||
jamPanggil: "15:10",
|
||||
barcode: seedBarcodeE3,
|
||||
noAntrian: `F-EA015 | Online - ${seedBarcodeE3}`, // Counter 15: Fast Track Eksekutif
|
||||
shift: "Shift 2",
|
||||
klinik: "SARAF",
|
||||
fastTrack: "YA", // Fast Track Patient
|
||||
pembayaran: "Eksekutif",
|
||||
status: "waiting",
|
||||
processStage: "loket",
|
||||
createdAt: new Date().toISOString(),
|
||||
registrationType: 'online',
|
||||
visitType: 'SEKARANG',
|
||||
visitDate: new Date().toISOString().substring(0, 10),
|
||||
namaDokter: "Dr. Citra Dewi, Sp.S",
|
||||
penanggungJawab: "Dr. Citra Dewi", // Fast Track data
|
||||
alasanFastTrack: "Pasien Eksekutif prioritas", // Fast Track data
|
||||
},
|
||||
{
|
||||
no: 16,
|
||||
jamPanggil: "16:30",
|
||||
barcode: seedBarcodeE4,
|
||||
noAntrian: `EA016 | Online - ${seedBarcodeE4}`, // Counter 16: Non-fast track Eksekutif
|
||||
shift: "Shift 1",
|
||||
klinik: "THT",
|
||||
fastTrack: "TIDAK",
|
||||
pembayaran: "Eksekutif",
|
||||
status: "waiting",
|
||||
processStage: "loket",
|
||||
createdAt: new Date().toISOString(),
|
||||
registrationType: 'online',
|
||||
visitType: 'SEKARANG',
|
||||
visitDate: new Date().toISOString().substring(0, 10),
|
||||
namaDokter: "Dr. Dedi Kurniawan, Sp.THT",
|
||||
penanggungJawab: null,
|
||||
alasanFastTrack: null,
|
||||
},
|
||||
];
|
||||
|
||||
const cloneSeed = () => seedPatients.map(p => ({ ...p }));
|
||||
|
||||
// Initialize counters from seed data to ensure numbering continues correctly
|
||||
// Counter SHARED untuk semua payment group dan semua jenis pasien
|
||||
const initializeCountersFromSeed = () => {
|
||||
if (typeof window === 'undefined') return; // Skip in SSR
|
||||
|
||||
const today = new Date().toISOString().split('T')[0]; // YYYY-MM-DD
|
||||
|
||||
// Parse seed data to find max counter (SHARED untuk semua)
|
||||
let maxCounter = 0;
|
||||
|
||||
seedPatients.forEach(patient => {
|
||||
if (!patient.noAntrian) return;
|
||||
|
||||
// Extract queue number from noAntrian (format: "F-RA001 | ..." or "RA001 | ..." or "EA001 | ...")
|
||||
// Remove "F-" prefix untuk mendapatkan nomor asli
|
||||
const queueNumberMatch = patient.noAntrian.match(/^(?:F-)?([RE])([A-N])(\d+)/);
|
||||
if (!queueNumberMatch) return;
|
||||
|
||||
const loketLetter = queueNumberMatch[2]; // A-N
|
||||
const number = parseInt(queueNumberMatch[3], 10); // 001-999
|
||||
|
||||
// Calculate counter from loket and number
|
||||
// Loket A = 1-999, Loket B = 1000-1998, etc.
|
||||
const loketIndex = loketLetter.charCodeAt(0) - 65; // A=0, B=1, etc.
|
||||
const counter = (loketIndex * 999) + number;
|
||||
|
||||
// Update max counter (shared untuk semua)
|
||||
if (counter > maxCounter) {
|
||||
maxCounter = counter;
|
||||
}
|
||||
});
|
||||
|
||||
// Initialize localStorage counter (SHARED untuk semua payment group)
|
||||
if (maxCounter > 0) {
|
||||
const counterKey = `queue_counter_loket_shared_${today}`;
|
||||
const existing = localStorage.getItem(counterKey);
|
||||
if (!existing || parseInt(existing, 10) < maxCounter) {
|
||||
localStorage.setItem(counterKey, maxCounter.toString());
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Initialize counters from seed data
|
||||
initializeCountersFromSeed();
|
||||
|
||||
// Initialize state - will be automatically hydrated from localStorage by pinia-plugin-persistedstate
|
||||
// If localStorage has data, it will override these defaults
|
||||
const allPatients = ref(cloneSeed());
|
||||
@@ -388,13 +586,13 @@ export const useQueueStore = defineStore('queue', () => {
|
||||
return { success: false, message: "Tidak ada pasien yang menunggu untuk dipanggil" };
|
||||
}
|
||||
|
||||
// Langsung update status menjadi 'waiting'
|
||||
// Langsung update status menjadi 'waiting' (sudah dipanggil, bisa check-in)
|
||||
const callTimestamp = new Date().toISOString();
|
||||
const index = allPatients.value.findIndex(p => p.no === nextPatient.no);
|
||||
if (index !== -1) {
|
||||
allPatients.value[index] = {
|
||||
...allPatients.value[index],
|
||||
status: "waiting",
|
||||
status: "waiting", // Status "waiting" = sudah dipanggil, bisa check-in
|
||||
lastCalledAt: callTimestamp // Track waktu panggilan untuk multiple calls
|
||||
};
|
||||
}
|
||||
@@ -748,6 +946,138 @@ export const useQueueStore = defineStore('queue', () => {
|
||||
};
|
||||
};
|
||||
|
||||
// Pindah pasien ke klinik ruang lain dengan nomor antrian tetap
|
||||
const pindahKlinikRuang = (patient, targetKlinikRuang, targetRuang) => {
|
||||
const patientIndex = allPatients.value.findIndex(p => p.no === patient.no);
|
||||
|
||||
if (patientIndex === -1) {
|
||||
return { success: false, message: "Pasien tidak ditemukan" };
|
||||
}
|
||||
|
||||
const currentPatient = allPatients.value[patientIndex];
|
||||
|
||||
// Jika pasien sudah punya antrean klinik ruang, update antreannya
|
||||
if (currentPatient.processStage === 'klinik-ruang' && currentPatient.tipeLayanan) {
|
||||
const baseNoAntrian = currentPatient.noAntrian?.split(" |")[0] || currentPatient.barcode || '';
|
||||
|
||||
// Update dengan klinik dan ruang baru, tapi nomor antrian tetap sama
|
||||
allPatients.value[patientIndex] = {
|
||||
...currentPatient,
|
||||
klinik: targetKlinikRuang.namaKlinik,
|
||||
ruang: targetRuang.namaRuang,
|
||||
kodeKlinik: targetKlinikRuang.kodeKlinik,
|
||||
nomorRuang: targetRuang.nomorRuang,
|
||||
nomorScreen: targetRuang.nomorScreen,
|
||||
// Nomor antrian tetap sama
|
||||
noAntrian: `${baseNoAntrian} | ${targetKlinikRuang.namaKlinik} - ${targetRuang.namaRuang} - ${currentPatient.tipeLayanan}`,
|
||||
noAntrianRuang: `${targetKlinikRuang.namaKlinik} - ${targetRuang.namaRuang} | ${baseNoAntrian}`
|
||||
};
|
||||
|
||||
// Clear current processing dari ruang lama jika ada
|
||||
const oldKey = `klinik-ruang-${currentPatient.kodeKlinik}-${currentPatient.nomorRuang}`;
|
||||
if (currentProcessingPatient.value[oldKey]?.no === currentPatient.no) {
|
||||
currentProcessingPatient.value[oldKey] = null;
|
||||
}
|
||||
} else {
|
||||
// Pasien belum digenerate tiket, hanya update ruang
|
||||
allPatients.value[patientIndex] = {
|
||||
...currentPatient,
|
||||
klinik: targetKlinikRuang.namaKlinik,
|
||||
ruang: targetRuang.namaRuang,
|
||||
kodeKlinik: targetKlinikRuang.kodeKlinik,
|
||||
nomorRuang: targetRuang.nomorRuang,
|
||||
nomorScreen: targetRuang.nomorScreen
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
success: true,
|
||||
message: `Pasien berhasil dipindah ke ${targetKlinikRuang.namaKlinik} Ruang ${targetRuang.nomorRuang}`,
|
||||
patient: allPatients.value[patientIndex]
|
||||
};
|
||||
};
|
||||
|
||||
// Konsultasi: pindah pasien ke klinik ruang lain dengan nomor antrian baru (prefix K- atau KF-)
|
||||
const konsultasiKlinikRuang = (patient, targetKlinikRuang, targetRuang, tipeLayanan = 'Pemeriksaan Awal') => {
|
||||
const patientIndex = allPatients.value.findIndex(p => p.no === patient.no);
|
||||
|
||||
if (patientIndex === -1) {
|
||||
return { success: false, message: "Pasien tidak ditemukan" };
|
||||
}
|
||||
|
||||
const sourcePatient = allPatients.value[patientIndex];
|
||||
|
||||
// Cek apakah sudah ada antrean konsultasi di ruang tujuan
|
||||
const existingKonsultasi = allPatients.value.find(p =>
|
||||
p.referencePatient === sourcePatient.noAntrian &&
|
||||
p.kodeKlinik === targetKlinikRuang.kodeKlinik &&
|
||||
p.nomorRuang === targetRuang.nomorRuang &&
|
||||
p.processStage === 'klinik-ruang' &&
|
||||
(p.noAntrian?.startsWith('K-') || p.noAntrian?.startsWith('KF-'))
|
||||
);
|
||||
|
||||
if (existingKonsultasi) {
|
||||
return {
|
||||
success: false,
|
||||
message: `Pasien sudah memiliki antrean konsultasi di ${targetKlinikRuang.namaKlinik} Ruang ${targetRuang.nomorRuang}`
|
||||
};
|
||||
}
|
||||
|
||||
// Generate queue number untuk konsultasi
|
||||
const roomQueues = allPatients.value.filter(p =>
|
||||
p.kodeKlinik === targetKlinikRuang.kodeKlinik &&
|
||||
p.nomorRuang === targetRuang.nomorRuang &&
|
||||
p.tipeLayanan === tipeLayanan &&
|
||||
p.processStage === 'klinik-ruang' &&
|
||||
(p.noAntrian?.startsWith('K-') || p.noAntrian?.startsWith('KF-'))
|
||||
);
|
||||
|
||||
const queueNumber = roomQueues.length + 1;
|
||||
const prefix = tipeLayanan === 'Pemeriksaan Awal' ? 'PA' : 'TD';
|
||||
|
||||
// Tentukan prefix konsultasi: KF- untuk Fast Track, K- untuk normal
|
||||
const isFastTrack = sourcePatient.fastTrack === "YA";
|
||||
const konsultasiPrefix = isFastTrack ? 'KF-' : 'K-';
|
||||
const queueNumberStr = String(queueNumber).padStart(3, "0");
|
||||
const newNoAntrian = `${konsultasiPrefix}${prefix}${queueNumberStr}`;
|
||||
|
||||
const newNo = allPatients.value.length + 1;
|
||||
const timestamp = new Date();
|
||||
|
||||
const newPatient = {
|
||||
no: newNo,
|
||||
jamPanggil: `${String(timestamp.getHours()).padStart(2, "0")}:${String(
|
||||
timestamp.getMinutes()
|
||||
).padStart(2, "0")}`,
|
||||
barcode: sourcePatient.barcode,
|
||||
noAntrian: `${newNoAntrian} | ${targetKlinikRuang.namaKlinik} - ${targetRuang.namaRuang} - ${tipeLayanan}`,
|
||||
noAntrianRuang: `${targetKlinikRuang.namaKlinik} - ${targetRuang.namaRuang} | ${newNoAntrian}`,
|
||||
shift: sourcePatient.shift || "Shift 1",
|
||||
klinik: targetKlinikRuang.namaKlinik,
|
||||
ruang: targetRuang.namaRuang,
|
||||
kodeKlinik: targetKlinikRuang.kodeKlinik,
|
||||
nomorRuang: targetRuang.nomorRuang,
|
||||
nomorScreen: targetRuang.nomorScreen,
|
||||
tipeLayanan: tipeLayanan,
|
||||
fastTrack: sourcePatient.fastTrack || "TIDAK",
|
||||
pembayaran: sourcePatient.pembayaran || "UMUM",
|
||||
status: "waiting",
|
||||
processStage: "klinik-ruang",
|
||||
createdAt: sourcePatient.createdAt || timestamp.toISOString(), // Gunakan createdAt dari pasien awal
|
||||
referencePatient: sourcePatient.noAntrian,
|
||||
sourcePatientNo: sourcePatient.no,
|
||||
isKonsultasi: true, // Flag untuk konsultasi
|
||||
};
|
||||
|
||||
allPatients.value.push(newPatient);
|
||||
|
||||
return {
|
||||
success: true,
|
||||
message: `Antrean konsultasi berhasil dibuat: ${newNoAntrian} untuk ${targetKlinikRuang.namaKlinik} Ruang ${targetRuang.nomorRuang}`,
|
||||
patient: newPatient,
|
||||
};
|
||||
};
|
||||
|
||||
// Scan barcode dan generate antrean klinik ruang baru
|
||||
const scanAndCreateAntreanKlinikRuang = (barcodeInput, klinikRuang, ruang, tipeLayanan = 'Pemeriksaan Awal') => {
|
||||
// Clean input - remove whitespace and handle prefix letters
|
||||
@@ -798,11 +1128,20 @@ export const useQueueStore = defineStore('queue', () => {
|
||||
p.kodeKlinik === klinikRuang.kodeKlinik &&
|
||||
p.nomorRuang === ruang.nomorRuang &&
|
||||
p.tipeLayanan === tipeLayanan &&
|
||||
p.processStage === 'klinik-ruang'
|
||||
p.processStage === 'klinik-ruang' &&
|
||||
!p.noAntrian?.startsWith('K-') && // Exclude konsultasi
|
||||
!p.noAntrian?.startsWith('KF-') // Exclude konsultasi Fast Track
|
||||
);
|
||||
|
||||
const queueNumber = roomQueues.length + 1;
|
||||
const prefix = tipeLayanan === 'Pemeriksaan Awal' ? 'PA' : 'TD';
|
||||
|
||||
// Tentukan prefix untuk Fast Track: F- untuk Fast Track
|
||||
const isFastTrack = sourcePatient.fastTrack === "YA";
|
||||
const fastTrackPrefix = isFastTrack ? 'F-' : '';
|
||||
const queueNumberStr = String(queueNumber).padStart(3, "0");
|
||||
const newNoAntrian = `${fastTrackPrefix}${prefix}${queueNumberStr}`;
|
||||
|
||||
const newNo = allPatients.value.length + 1;
|
||||
const timestamp = new Date();
|
||||
|
||||
@@ -812,8 +1151,8 @@ export const useQueueStore = defineStore('queue', () => {
|
||||
timestamp.getMinutes()
|
||||
).padStart(2, "0")}`,
|
||||
barcode: sourcePatient.barcode,
|
||||
noAntrian: `${prefix}${String(queueNumber).padStart(3, "0")} | ${klinikRuang.namaKlinik} - ${ruang.namaRuang} - ${tipeLayanan}`,
|
||||
noAntrianRuang: `${klinikRuang.namaKlinik} - ${ruang.namaRuang} | ${prefix}${String(queueNumber).padStart(3, "0")}`,
|
||||
noAntrian: `${newNoAntrian} | ${klinikRuang.namaKlinik} - ${ruang.namaRuang} - ${tipeLayanan}`,
|
||||
noAntrianRuang: `${klinikRuang.namaKlinik} - ${ruang.namaRuang} | ${newNoAntrian}`,
|
||||
shift: sourcePatient.shift || "Shift 1",
|
||||
klinik: klinikRuang.namaKlinik,
|
||||
ruang: ruang.namaRuang,
|
||||
@@ -825,7 +1164,7 @@ export const useQueueStore = defineStore('queue', () => {
|
||||
pembayaran: sourcePatient.pembayaran || "UMUM",
|
||||
status: "waiting",
|
||||
processStage: "klinik-ruang",
|
||||
createdAt: timestamp.toISOString(),
|
||||
createdAt: sourcePatient.createdAt || timestamp.toISOString(), // Gunakan createdAt dari pasien awal
|
||||
referencePatient: sourcePatient.noAntrian,
|
||||
sourcePatientNo: sourcePatient.no,
|
||||
};
|
||||
@@ -1001,24 +1340,22 @@ export const useQueueStore = defineStore('queue', () => {
|
||||
};
|
||||
|
||||
// Helper function untuk generate nomor antrean baru
|
||||
// Format: 2 huruf (kode klinik) + 3 digit (001-999)
|
||||
// Generate nomor antrian dengan format baru untuk anjungan: R/E + Loket (A-N) + 3 digit
|
||||
// Format: R/E + Loket (A-N) + 3 digit
|
||||
// Format: R/E (jenis pelayanan Reguler/Eksekutif) + A-N (nomor loket) + 3 digit angka
|
||||
// Contoh: RA001, EA001, RB001, RB002
|
||||
// - R = Reguler (untuk pasien Reguler/BPJS)
|
||||
// - E = Eksekutif (untuk pasien Eksekutif/Grand Pavilion)
|
||||
// Urutan terpisah untuk UMUM dan JKN/BPJS
|
||||
// IMPORTANT: Counter SHARED untuk semua payment group (JKN/UMUM) dan semua jenis (fast track/non-fast track)
|
||||
// Prefix "F-" hanya untuk menandai status fast track, bukan untuk memisahkan counter
|
||||
// Setiap loket menampung maksimal 999 nomor (001-999)
|
||||
const generateQueueNumber = (clinic, paymentType, isEksekutif = false) => {
|
||||
// Tentukan prefix jenis pelayanan: R untuk Reguler, E untuk Eksekutif (Grand Pavilion)
|
||||
const serviceType = isEksekutif ? 'E' : 'R';
|
||||
|
||||
// Tentukan payment group untuk counter terpisah (UMUM atau JKN/BPJS)
|
||||
const paymentGroup = paymentType === 'BPJS' || paymentType === 'JKN' ? 'JKN' : 'UMUM';
|
||||
|
||||
// Get counter untuk payment group ini per hari
|
||||
// Counter SHARED untuk semua payment group dan semua jenis pasien
|
||||
// Tidak ada pemisahan counter berdasarkan payment group atau fast track
|
||||
const today = new Date().toISOString().split('T')[0]; // YYYY-MM-DD
|
||||
const counterKey = `queue_counter_loket_${paymentGroup}_${today}`;
|
||||
const counterKey = `queue_counter_loket_shared_${today}`;
|
||||
|
||||
// Get current counter dari localStorage
|
||||
let counter = 0;
|
||||
@@ -1068,7 +1405,7 @@ export const useQueueStore = defineStore('queue', () => {
|
||||
};
|
||||
|
||||
// Register patient from Anjungan (onsite registration)
|
||||
const registerPatientFromAnjungan = (clinic, paymentType, visitType = 'SEKARANG', visitDate = null, shift = 'Shift 1', namaDokter = null, isFastTrack = false) => {
|
||||
const registerPatientFromAnjungan = (clinic, paymentType, visitType = 'SEKARANG', visitDate = null, shift = 'Shift 1', namaDokter = null, isFastTrack = false, fastTrackData = null) => {
|
||||
const newNo = allPatients.value.length > 0
|
||||
? Math.max(...allPatients.value.map(p => p.no)) + 1
|
||||
: 1;
|
||||
@@ -1087,9 +1424,9 @@ export const useQueueStore = defineStore('queue', () => {
|
||||
|
||||
// Generate nomor antrean dengan format baru: R/E + Loket (A-N) + 3 digit
|
||||
// Format: RA001 (Reguler), EA001 (Eksekutif/Grand Pavilion), RB001, RB002, dll
|
||||
// Untuk Fast Track, tambahkan prefix "F" di depan: FRA001, FEA001, dll
|
||||
// Untuk Fast Track, tambahkan prefix "F-" di depan: F-RA001, F-EA001, dll
|
||||
const queueNumber = generateQueueNumber(clinic, paymentType, isEksekutif);
|
||||
const finalQueueNumber = isFastTrack ? `F${queueNumber}` : queueNumber;
|
||||
const finalQueueNumber = isFastTrack ? `F-${queueNumber}` : queueNumber;
|
||||
const noAntrian = `${finalQueueNumber} | Onsite - ${barcode}`;
|
||||
|
||||
// Status awal untuk pasien dari anjungan adalah "menunggu" (belum dipanggil)
|
||||
@@ -1112,6 +1449,9 @@ export const useQueueStore = defineStore('queue', () => {
|
||||
visitType: visitType,
|
||||
visitDate: visitDate || timestamp.toISOString().substring(0, 10),
|
||||
namaDokter: namaDokter || null, // Nama dokter hanya untuk pasien Eksekutif
|
||||
// Fast Track data
|
||||
penanggungJawab: (isFastTrack && fastTrackData) ? fastTrackData.penanggungJawab : null,
|
||||
alasanFastTrack: (isFastTrack && fastTrackData) ? fastTrackData.alasanFastTrack : null,
|
||||
};
|
||||
|
||||
allPatients.value.push(newPatient);
|
||||
@@ -1164,18 +1504,26 @@ export const useQueueStore = defineStore('queue', () => {
|
||||
}
|
||||
|
||||
// Check if noAntrian includes the input (case insensitive)
|
||||
// Handle format "F-RA001" by removing "F-" prefix for comparison
|
||||
const noAntrianUpper = (p.noAntrian || '').toUpperCase();
|
||||
if (noAntrianUpper.includes(cleanInput) || noAntrianUpper.includes(patientIdOrBarcode)) {
|
||||
const noAntrianWithoutPrefix = noAntrianUpper.replace(/^F-/, ''); // Remove "F-" prefix if exists
|
||||
const cleanInputWithoutPrefix = cleanInputUpper.replace(/^F-/, ''); // Remove "F-" prefix from input if exists
|
||||
|
||||
if (noAntrianUpper.includes(cleanInput) ||
|
||||
noAntrianUpper.includes(patientIdOrBarcode) ||
|
||||
noAntrianWithoutPrefix.includes(cleanInputWithoutPrefix) ||
|
||||
noAntrianWithoutPrefix === cleanInputWithoutPrefix) {
|
||||
console.log('✅ Found by noAntrian:', p.noAntrian);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Try to extract number from noAntrian (e.g., "UM0014 | Onsite - ..." -> "0014")
|
||||
const noAntrianNumber = noAntrianUpper.match(/([A-Z]+)(\d+)/);
|
||||
if (noAntrianNumber) {
|
||||
const extractedNumber = noAntrianNumber[2];
|
||||
const inputNumber = cleanInput.replace(/[^0-9]/g, '');
|
||||
if (inputNumber && extractedNumber.includes(inputNumber) || inputNumber.includes(extractedNumber)) {
|
||||
// Try to extract number from noAntrian (e.g., "F-RA001 | Onsite - ..." -> "RA001" -> "001")
|
||||
// Handle format "F-RA001" by extracting after "F-" prefix
|
||||
const noAntrianMatch = noAntrianUpper.match(/^(?:F-)?([A-Z]+)(\d+)/);
|
||||
if (noAntrianMatch) {
|
||||
const extractedNumber = noAntrianMatch[2];
|
||||
const inputNumber = cleanInputWithoutPrefix.replace(/[^0-9]/g, '');
|
||||
if (inputNumber && (extractedNumber.includes(inputNumber) || inputNumber.includes(extractedNumber))) {
|
||||
console.log('✅ Found by extracted number from noAntrian');
|
||||
return true;
|
||||
}
|
||||
@@ -1269,6 +1617,8 @@ export const useQueueStore = defineStore('queue', () => {
|
||||
callNextKlinikRuang,
|
||||
processPatientKlinikRuang,
|
||||
changeKlinik,
|
||||
pindahKlinikRuang,
|
||||
konsultasiKlinikRuang,
|
||||
processNextQueue,
|
||||
getPatientsByStage,
|
||||
getTotalPasienByStage,
|
||||
|
||||
Reference in New Issue
Block a user