update post api status dan API data pasien ruang

This commit is contained in:
bagus-arie05
2026-02-05 12:00:33 +07:00
parent c2d9023418
commit e2a5d43e76
4 changed files with 672 additions and 34 deletions
+3
View File
@@ -117,6 +117,9 @@ export default defineNuxtConfig({
'/stats-api/**': {
proxy: 'http://10.10.150.100:8084/api/v1/**'
},
'/visit-api/**': {
proxy: 'http://10.10.150.100:8084/api/v1/**'
},
},
vite: {
+472 -10
View File
@@ -890,6 +890,25 @@ const showFilterDialog = ref({});
const filterOptions = ref({});
const klinikRuangSearch = ref('');
// API Patient Data
const apiPatients = ref([]);
const isLoadingPatients = ref(false);
const apiError = ref(null);
// Helper: Check if a patient is from today
const isTodayPatient = (patient) => {
if (!patient.createdAt && !patient.jamPanggil) return false;
const patientDate = new Date(patient.createdAt || patient.jamPanggil);
const today = new Date();
return (
patientDate.getDate() === today.getDate() &&
patientDate.getMonth() === today.getMonth() &&
patientDate.getFullYear() === today.getFullYear()
);
};
// Initialize filter options for each room
const initializeFilterOptions = (ruang) => {
if (!filterOptions.value[ruang.nomorRuang]) {
@@ -933,17 +952,454 @@ const showSnackbar = (message, color = 'success') => {
snackbar.value = true;
};
// Get all patients for room (hanya pasien dari processStage 'klinik-ruang')
const getAllPatientsForRoom = (ruang) => {
return queueStore.allPatients
.filter(p =>
p.kodeKlinik === klinikData.value?.kodeKlinik &&
p.nomorRuang === ruang.nomorRuang &&
p.ruang === ruang.namaRuang &&
p.processStage === 'klinik-ruang' &&
// Include semua pasien dengan status yang relevan
(p.status === 'anjungan' || p.status === 'di-loket' || p.status === 'terlambat' || p.status === 'pending')
/**
* Fetch patients from API for the clinic
* Uses filters: klinik_id, klinik_ruang_id, active, limit
*/
const fetchPatientsFromAPI = async () => {
if (!klinikData.value) {
console.warn('⚠️ Klinik data not available');
return;
}
isLoadingPatients.value = true;
apiError.value = null;
try {
// Get klinik_id from clinicStore - find clinic by kodeKlinik
const clinic = clinicStore.clinics.find(c =>
c.kode === klinikData.value.kodeKlinik &&
(!jenisLayanan.value || c.jenisLayanan === jenisLayanan.value)
);
if (!clinic || !clinic.id) {
console.warn('⚠️ Klinik ID not found for', klinikData.value.kodeKlinik);
console.log('Available clinics:', clinicStore.clinics.map(c => ({ kode: c.kode, id: c.id, jenisLayanan: c.jenisLayanan })));
isLoadingPatients.value = false;
return;
}
const klinikId = clinic.id;
// Build API URL with filters - using Nuxt proxy to avoid CORS
const baseUrl = '/visit-api/visit';
const params = new URLSearchParams({
active: '1',
klinik_id: klinikId.toString(),
limit: '500'
});
// If there are rooms, fetch data for each room
// For now, we'll fetch all patients for the clinic and filter by room on the client side
const url = `${baseUrl}?${params.toString()}`;
console.log('🔄 Fetching patients from:', url);
console.log('📋 Using clinic ID:', klinikId, 'for clinic code:', klinikData.value.kodeKlinik);
const response = await fetch(url);
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const rawResponse = await response.json();
console.log('📦 Raw API Response:', rawResponse);
// Extract data array from response wrapper
const data = rawResponse?.data || [];
const message = rawResponse?.message || '';
console.log('📋 API Message:', message);
console.log('📊 Data array length:', data.length);
// Process the response data
if (Array.isArray(data) && data.length > 0) {
// Map API data to our internal format
apiPatients.value = [];
data.forEach((visit, index) => {
// Each visit can have multiple healthcare_services (sub-services/rooms)
const healthcareServices = visit.healthcare_services || [];
if (healthcareServices.length > 0) {
healthcareServices.forEach(service => {
// Convert room ID to string for nomorRuang matching
const roomId = service.fk_ms_sub_healthcare_service_id;
const roomIdString = roomId ? String(roomId) : null;
// Extract status from visit_statuses array (use latest status)
const visitStatuses = visit.visit_statuses || [];
const latestStatus = visitStatuses.length > 0
? visitStatuses[visitStatuses.length - 1]
: null;
// Map status from API or default to 'di-loket' (patients just arrived from loket)
// Status 'pemeriksaan' will be set explicitly when patient is transferred from loket
let patientStatus = 'di-loket'; // Default for klinik-ruang patients
if (latestStatus && latestStatus.desc) {
const desc = latestStatus.desc.toLowerCase();
if (desc.includes('pemeriksaan') || desc.includes('sedang diproses')) {
patientStatus = 'pemeriksaan';
} else if (desc.includes('check-in') || desc.includes('loket')) {
patientStatus = 'di-loket';
}
}
const mappedPatient = {
no: visit.id || (10000 + index),
barcode: visit.visit_code || service.ticket || '', // Prioritize visit_code
noAntrian: service.ticket || visit.visit_code || '',
jamPanggil: service.check_in_datetime || visit.registration_datetime || '',
klinik: service.healthcare_service_name || klinikData.value.namaKlinik,
kodeKlinik: klinikData.value.kodeKlinik,
klinikId: service.fk_ms_healthcare_service_id || klinikId,
ruang: service.sub_healthcare_service_name || '',
nomorRuang: roomIdString, // Use string version of room ID
pembayaran: service.payment_type_name || visit.payment_type_name || '', // Payment type from service level
status: patientStatus, // Status from API or default 'di-loket'
processStage: 'klinik-ruang',
createdAt: visit.registration_datetime || new Date().toISOString(),
visitType: visit.visit_type_name || 'ONSITE',
noRM: visit.norm || '',
fastTrack: 'TIDAK',
registrationType: 'api',
visitId: visit.id,
visitCode: visit.visit_code,
// Store original API data for reference
_apiData: { visit, service }
};
// Only add if patient is from today
if (isTodayPatient(mappedPatient)) {
apiPatients.value.push(mappedPatient);
}
});
} else {
// If no healthcare_services, create one entry for the visit
// Extract status from visit_statuses
const visitStatuses = visit.visit_statuses || [];
const latestStatus = visitStatuses.length > 0
? visitStatuses[visitStatuses.length - 1]
: null;
let patientStatus = 'di-loket';
if (latestStatus && latestStatus.desc) {
const desc = latestStatus.desc.toLowerCase();
if (desc.includes('pemeriksaan') || desc.includes('sedang diproses')) {
patientStatus = 'pemeriksaan';
} else if (desc.includes('check-in') || desc.includes('loket')) {
patientStatus = 'di-loket';
}
}
const mappedPatient = {
no: visit.id || (10000 + index),
barcode: visit.visit_code || '', // Use visit_code for barcode
noAntrian: visit.visit_code || '',
jamPanggil: visit.registration_datetime || '',
klinik: klinikData.value.namaKlinik,
kodeKlinik: klinikData.value.kodeKlinik,
klinikId: klinikId,
ruang: '',
nomorRuang: null,
pembayaran: visit.payment_type_name || '', // Payment type from visit level
status: patientStatus, // Status from API or default 'di-loket'
processStage: 'klinik-ruang',
createdAt: visit.registration_datetime || new Date().toISOString(),
visitType: visit.visit_type_name || 'ONSITE',
noRM: visit.norm || '',
fastTrack: 'TIDAK',
registrationType: 'api',
visitId: visit.id,
visitCode: visit.visit_code,
_apiData: { visit }
};
// Only add if patient is from today
if (isTodayPatient(mappedPatient)) {
apiPatients.value.push(mappedPatient);
}
}
});
const totalVisits = data.length;
const totalPatientEntries = apiPatients.value.length;
console.log(`✅ Loaded ${totalPatientEntries} patient entries from ${totalVisits} visits (today only)`);
console.log('📋 Sample patient data:', apiPatients.value.slice(0, 2).map(p => ({
ticket: p.noAntrian,
ruang: p.ruang,
nomorRuang: p.nomorRuang,
pembayaran: p.pembayaran,
kodeKlinik: p.kodeKlinik,
createdAt: p.createdAt
})));
// Merge with queueStore.allPatients to maintain consistency
mergeApiPatientsToStore();
} else {
console.warn('⚠️ Unexpected API response format:', data);
apiPatients.value = [];
}
} catch (error) {
console.error('❌ Error fetching patients:', error);
apiError.value = error.message;
showSnackbar(`Gagal memuat data pasien: ${error.message}`, 'error');
} finally {
isLoadingPatients.value = false;
}
};
/**
* Fetch patients for a specific room
*/
const fetchPatientsForRoom = async (ruang) => {
if (!klinikData.value || !ruang) {
console.warn('⚠️ Klinik data or room not available');
return;
}
isLoadingPatients.value = true;
apiError.value = null;
try {
// Get klinik_id from masterStore ruangData
const ruangData = masterStore.ruangData || [];
const currentKlinik = ruangData.find(r =>
r.kodeKlinik === klinikData.value.kodeKlinik &&
(!jenisLayanan.value || r.jenisLayanan === jenisLayanan.value)
);
if (!currentKlinik || !currentKlinik.idKlinik) {
console.warn('⚠️ Klinik ID not found');
isLoadingPatients.value = false;
return;
}
const klinikId = currentKlinik.idKlinik;
// Build API URL with filters including room ID - using Nuxt proxy to avoid CORS
const baseUrl = '/visit-api/visit';
const params = new URLSearchParams({
active: '1',
klinik_id: klinikId.toString(),
limit: '500'
});
// Add room filter if room has an ID
if (ruang.idRuang) {
params.append('klinik_ruang_id', ruang.idRuang.toString());
}
const url = `${baseUrl}?${params.toString()}`;
console.log('🔄 Fetching patients for room from:', url);
const response = await fetch(url);
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const rawResponse = await response.json();
// Extract data array from response wrapper
const data = rawResponse?.data || [];
// Process and merge the response data
if (Array.isArray(data) && data.length > 0) {
const roomPatients = [];
data.forEach((visit, index) => {
const healthcareServices = visit.healthcare_services || [];
if (healthcareServices.length > 0) {
healthcareServices.forEach(service => {
// Convert room ID to string for nomorRuang matching
const roomId = service.fk_ms_sub_healthcare_service_id;
const roomIdString = roomId ? String(roomId) : null;
// Extract status from visit_statuses
const visitStatuses = visit.visit_statuses || [];
const latestStatus = visitStatuses.length > 0
? visitStatuses[visitStatuses.length - 1]
: null;
let patientStatus = 'di-loket';
if (latestStatus && latestStatus.desc) {
const desc = latestStatus.desc.toLowerCase();
if (desc.includes('pemeriksaan') || desc.includes('sedang diproses')) {
patientStatus = 'pemeriksaan';
} else if (desc.includes('check-in') || desc.includes('loket')) {
patientStatus = 'di-loket';
}
}
const mappedPatient = {
no: visit.id || (10000 + index),
barcode: visit.visit_code || service.ticket || '', // Prioritize visit_code
noAntrian: service.ticket || visit.visit_code || '',
jamPanggil: service.check_in_datetime || visit.registration_datetime || '',
klinik: service.healthcare_service_name || klinikData.value.namaKlinik,
kodeKlinik: klinikData.value.kodeKlinik,
klinikId: service.fk_ms_healthcare_service_id || klinikId,
ruang: ruang.namaRuang,
nomorRuang: roomIdString, // Use string version of room ID
nomorScreen: ruang.nomorScreen,
pembayaran: service.payment_type_name || visit.payment_type_name || '', // Payment type from service level
status: patientStatus, // Status from API or default 'di-loket'
processStage: 'klinik-ruang',
createdAt: visit.registration_datetime || new Date().toISOString(),
visitType: visit.visit_type_name || 'ONSITE',
noRM: visit.norm || '',
fastTrack: 'TIDAK',
registrationType: 'api',
visitId: visit.id,
visitCode: visit.visit_code,
_apiData: { visit, service }
};
// Only add if patient is from today
if (isTodayPatient(mappedPatient)) {
roomPatients.push(mappedPatient);
}
});
} else {
// Extract status from visit_statuses
const visitStatuses = visit.visit_statuses || [];
const latestStatus = visitStatuses.length > 0
? visitStatuses[visitStatuses.length - 1]
: null;
let patientStatus = 'di-loket';
if (latestStatus && latestStatus.desc) {
const desc = latestStatus.desc.toLowerCase();
if (desc.includes('pemeriksaan') || desc.includes('sedang diproses')) {
patientStatus = 'pemeriksaan';
} else if (desc.includes('check-in') || desc.includes('loket')) {
patientStatus = 'di-loket';
}
}
const mappedPatient = {
no: visit.id || (10000 + index),
barcode: visit.visit_code || '', // Use visit_code for barcode
noAntrian: visit.visit_code || '',
jamPanggil: visit.registration_datetime || '',
klinik: klinikData.value.namaKlinik,
kodeKlinik: klinikData.value.kodeKlinik,
klinikId: klinikId,
ruang: ruang.namaRuang,
nomorRuang: ruang.nomorRuang,
nomorScreen: ruang.nomorScreen,
pembayaran: visit.payment_type_name || '', // Payment type from visit level
status: patientStatus, // Status from API or default 'di-loket'
processStage: 'klinik-ruang',
createdAt: visit.registration_datetime || new Date().toISOString(),
visitType: visit.visit_type_name || 'ONSITE',
noRM: visit.norm || '',
fastTrack: 'TIDAK',
registrationType: 'api',
visitId: visit.id,
visitCode: visit.visit_code,
_apiData: { visit }
};
// Only add if patient is from today
if (isTodayPatient(mappedPatient)) {
roomPatients.push(mappedPatient);
}
}
});
// Update apiPatients for this specific room
// Remove old patients for this room and add new ones
apiPatients.value = [
...apiPatients.value.filter(p => p.nomorRuang !== ruang.nomorRuang),
...roomPatients
];
console.log(`✅ Loaded ${roomPatients.length} patients for room ${ruang.namaRuang}`);
mergeApiPatientsToStore();
}
} catch (error) {
console.error('❌ Error fetching patients for room:', error);
apiError.value = error.message;
} finally {
isLoadingPatients.value = false;
}
};
/**
* Merge API patients into queueStore.allPatients
*/
const mergeApiPatientsToStore = () => {
if (apiPatients.value.length === 0) return;
// Build a Set of unique identifiers from API patients for fast lookup
const apiPatientIds = new Set(
apiPatients.value.map(p => p.visitId || p.visitCode || p.barcode || p.noAntrian).filter(Boolean)
);
// Remove duplicates: remove any patient (API or not) that matches visitId, visitCode, barcode, or noAntrian
queueStore.allPatients = queueStore.allPatients.filter(p => {
const patientId = p.visitId || p.visitCode || p.barcode || p.noAntrian;
const isDuplicate = apiPatientIds.has(patientId);
if (isDuplicate) {
console.log('🗑️ Removing duplicate patient:', {
ticket: p.noAntrian,
barcode: p.barcode,
visitId: p.visitId,
registrationType: p.registrationType
});
}
return !isDuplicate;
});
// Add new API patients
queueStore.allPatients.push(...apiPatients.value);
console.log(`📊 Total patients in store: ${queueStore.allPatients.length}`);
};
// Get all patients for room (menggunakan data dari API)
const getAllPatientsForRoom = (ruang) => {
// Debug logging
console.log('🔍 Filtering patients for room:', {
ruangName: ruang.namaRuang,
ruangNomor: ruang.nomorRuang,
klinikCode: klinikData.value?.kodeKlinik
});
// Prioritize API patients, fallback to queueStore patients
const patients = queueStore.allPatients
.filter(p => {
const matches =
p.kodeKlinik === klinikData.value?.kodeKlinik &&
p.nomorRuang === ruang.nomorRuang &&
p.processStage === 'klinik-ruang' &&
// Include semua pasien dengan status yang relevan (including pemeriksaan for API patients)
(p.status === 'anjungan' || p.status === 'pemeriksaan' || p.status === 'di-loket' || p.status === 'terlambat' || p.status === 'pending');
if (!matches && p.kodeKlinik === klinikData.value?.kodeKlinik) {
console.log('❌ Patient did not match room:', {
ticket: p.noAntrian,
patientRoom: p.nomorRuang,
expectedRoom: ruang.nomorRuang,
stage: p.processStage,
status: p.status
});
}
return matches;
});
console.log(` ✅ Found ${patients.length} patients for room ${ruang.namaRuang}`);
return patients;
};
// Get filtered and sorted patients for room
@@ -1794,6 +2250,12 @@ onMounted(async () => {
await clinicStore.fetchRegulerClinics();
// Then sync rooms
await ruangStore.fetchRuangFromAPI();
// 2. Fetch patient data from API
if (klinikData.value) {
console.log('📋 Fetching patient data for clinic:', klinikData.value.kodeKlinik);
await fetchPatientsFromAPI();
}
} catch (error) {
console.error('❌ Error syncing data in AdminKlinikRuang:', error);
}
+134 -2
View File
@@ -617,7 +617,17 @@ const anjunganCount = computed(() => {
const nextQueueInfo = computed(() => {
const currentPatientNo = currentProcessingPatient.value?.no;
const nextPatient = (diLoketPatients.value || []).find(p => p.no !== currentPatientNo) || (diLoketPatients.value || [])[0];
const targetLoketId = parseInt(loketId.value);
// Filter diLoketPatients to only show patients for THIS loket
const loketFilteredPatients = (diLoketPatients.value || []).filter(p => {
// Only show patients assigned to this specific loket
return p.loketId && String(p.loketId) === String(targetLoketId);
});
// Find next patient (excluding current processing patient)
const nextPatient = loketFilteredPatients.find(p => p.no !== currentPatientNo) || loketFilteredPatients[0];
if (nextPatient) {
return `Antrian berikutnya: ${nextPatient.noAntrian.split(" |")[0]}`;
}
@@ -750,11 +760,132 @@ const buatAntreanKlinikRuang = async (klinikRuang, ruang) => {
return;
}
// POST to external visit ticket API FIRST to get ticket number
let apiTicketNumber = null;
let apiCallSuccess = false;
try {
// Map payment type: BPJS/JKN -> 2, UMUM/others -> 1
const paymentTypeId = (patient.pembayaran || '').toUpperCase().includes('BPJS') ||
(patient.pembayaran || '').toUpperCase().includes('JKN')
? 2 : 1;
// Map service type: Reguler -> 1, Eksekutif/Grand Pav -> 2
const serviceTypeId = (patient.pembayaran || '').toUpperCase().includes('EKSEKUTIF') ||
(patient.pembayaran || '').toUpperCase().includes('VIP') ||
(patient.pembayaran || '').toUpperCase().includes('GRAND')
? 2 : 1;
// Get idruangan from ruang object, ensure it's a number or null
let subHealthcareServiceId = null;
if (ruang.kodeRuang) {
const parsed = Number(ruang.kodeRuang);
subHealthcareServiceId = isNaN(parsed) ? null : parsed;
} else if (ruang.idruangan) {
const parsed = Number(ruang.idruangan);
subHealthcareServiceId = isNaN(parsed) ? null : parsed;
}
// Ensure healthcare_service_id is a number - MUST use actual clinic ID from clinicStore
const actualClinic = clinicStore.clinics.find(c => c.kode === klinikRuang.kodeKlinik);
const healthcareServiceId = actualClinic ? Number(actualClinic.id) : null;
if (!healthcareServiceId) {
console.error('❌ Could not find clinic ID for kode:', klinikRuang.kodeKlinik);
snackbarText.value = "Gagal membuat antrean ruang: ID klinik tidak ditemukan";
snackbarColor.value = "error";
snackbar.value = true;
closeKlinikRuangDialog();
return;
}
const visitTicketBody = {
visit_code: Number(patient.barcode),
healthcare_service_id: healthcareServiceId,
sub_healthcare_service_id: subHealthcareServiceId,
payment_type_id: paymentTypeId,
visit_status_id: [14, 15],
visit_type_id: 1,
service_type_id: serviceTypeId,
healthcare_type_id: 2
};
console.log('📤 Sending visit ticket to API:', visitTicketBody);
const visitResponse = await fetch('http://10.10.150.100:8084/api/v1/visit/ticket/klinik', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(visitTicketBody)
});
if (visitResponse.ok) {
const visitResult = await visitResponse.json();
console.log('✅ Visit ticket created successfully:', visitResult);
// Extract ticket number from API response
if (visitResult.healthcare_service && visitResult.healthcare_service.ticket) {
apiTicketNumber = visitResult.healthcare_service.ticket;
apiCallSuccess = true;
console.log('🎫 Using API ticket number:', apiTicketNumber);
} else {
console.error('❌ API response missing ticket number');
snackbarText.value = "Gagal membuat antrean ruang: Nomor tiket tidak ditemukan di response API";
snackbarColor.value = "error";
snackbar.value = true;
closeKlinikRuangDialog();
return;
}
} else {
// Parse error response
let errorMessage = "Gagal membuat antrean ruang";
try {
const errorData = await visitResponse.json();
console.error('⚠️ Visit ticket API error:', errorData);
// Check if it's a duplicate ticket error
if (errorData.message && errorData.message.toLowerCase().includes('already exists')) {
errorMessage = `Tiket klinik ruang sudah ada untuk pasien ini. ${errorData.message}`;
} else if (errorData.message) {
errorMessage = `Gagal membuat antrean ruang: ${errorData.message}`;
} else if (errorData.error) {
errorMessage = `Gagal membuat antrean ruang: ${errorData.error}`;
}
} catch (parseError) {
const errorText = await visitResponse.text();
console.error('⚠️ Visit ticket API returned error:', visitResponse.status, errorText);
errorMessage = `Gagal membuat antrean ruang (Status: ${visitResponse.status})`;
}
snackbarText.value = errorMessage;
snackbarColor.value = "error";
snackbar.value = true;
closeKlinikRuangDialog();
return;
}
} catch (apiError) {
console.error('❌ Error sending visit ticket to API:', apiError);
snackbarText.value = "Gagal membuat antrean ruang: Kesalahan koneksi ke API";
snackbarColor.value = "error";
snackbar.value = true;
closeKlinikRuangDialog();
return;
}
// Only create room queue if API call was successful
if (!apiCallSuccess || !apiTicketNumber) {
console.error('❌ Cannot create room queue without API ticket number');
return;
}
// Create room queue with API ticket number
const result = queueStore.createAntreanKlinikRuang(
klinikRuang,
ruang,
patient,
"loket"
"loket",
apiTicketNumber // Pass API ticket number
);
if (result.success && result.patient) {
@@ -769,6 +900,7 @@ const buatAntreanKlinikRuang = async (klinikRuang, ruang) => {
return;
}
}
snackbarText.value = result.message;
snackbarColor.value = result.success ? "success" : "error";
+63 -22
View File
@@ -169,7 +169,7 @@ export const useQueueStore = defineStore('queue', () => {
processStage: 'loket',
createdAt: apiPatient.tanggal || new Date().toISOString(),
registrationType: 'api',
visitType: 'SEKARANG',
visitType: 'Onsite',
visitDate: apiPatient.tanggal ? apiPatient.tanggal.split('T')[0] : new Date().toISOString().substring(0, 10),
namaDokter: null,
noRM: null,
@@ -325,13 +325,21 @@ export const useQueueStore = defineStore('queue', () => {
});
// 4. Remove existing patients that collide with new ones (to be replaced)
// AND remove stale 'api' patients for this loket
// This ensures API data ALWAYS takes precedence over local/seed data
// Remove ANY patient (local, seed, or api) with matching barcode/idtiket
allPatients.value = allPatients.value.filter(p => {
const key = p.idtiket ? `id-${p.idtiket}` : `bc-${p.barcode}`;
// Remove if it's being replaced by new batch
// Remove if it's being replaced by new API batch (matches by barcode or idtiket)
if (newPatientMap.has(key)) return false;
// Also check if barcode matches any new API patient (for cases where local has no idtiket)
// This prevents duplicates like barcode "2602050017" appearing as both BPJS (local) and JKN (API)
if (p.barcode) {
const barcodeMatches = patientsWithLoketId.some(newP => newP.barcode === p.barcode);
if (barcodeMatches) return false;
}
// Remove if it's a stale 'api' patient for this loket (that wasn't in the new batch)
if (p.registrationType === 'api' && String(p.loketId) === String(loketId)) return false;
@@ -1164,6 +1172,32 @@ export const useQueueStore = defineStore('queue', () => {
};
syncApiPatientStatus(allPatients.value[patientIndex], "di-loket");
message = `Pasien ${patientCode} berhasil check in dan masuk ke Tabel Loket Klinik`;
// POST to external API when patient finishes at loket
try {
fetch('http://10.10.150.131:8089/api/v1/tiket/selesai', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
idloket: String(patient.loketId || specificId || ""),
barcode: patient.barcode || "",
statuspasien: "9",
idklinikstatus: "2"
})
}).then(response => {
if (response.ok) {
console.log(`✅ [queueStore] Successfully posted selesai status for patient ${patient.barcode}`);
} else {
console.error(`⚠️ [queueStore] Failed to post selesai status for patient ${patient.barcode}:`, response.status);
}
}).catch(error => {
console.error(`❌ [queueStore] Error posting selesai status for patient ${patient.barcode}:`, error);
});
} catch (error) {
console.error(`❌ [queueStore] Error initiating selesai status update for patient ${patient.barcode}:`, error);
}
}
// Jika check-in di klinik, selesai
else if (adminType === 'klinik') {
@@ -1402,7 +1436,7 @@ export const useQueueStore = defineStore('queue', () => {
};
};
const createAntreanKlinikRuang = (klinikRuang, ruang, patient = null, adminType = 'klinik') => {
const createAntreanKlinikRuang = (klinikRuang, ruang, patient = null, adminType = 'klinik', apiTicketNumber = null) => {
const newNo = allPatients.value.length + 1;
const timestamp = new Date();
const barcode = patient ? patient.barcode : generateBarcode([], allPatients);
@@ -1410,24 +1444,32 @@ export const useQueueStore = defineStore('queue', () => {
// Generate nomor antrian baru dengan format: [huruf pertama poli + urutan abjad ruang + nomor antrian ruang]
// Contoh: "Anak" ruang 1 = "AA001" (A dari Anak, A dari ruang 1, 001 nomor antrian)
// 1. Ambil huruf pertama dari nama klinik/poli
const firstLetter = klinikRuang.namaKlinik.charAt(0).toUpperCase();
let newNoAntrian;
// 2. Konversi nomor ruang ke abjad (1 = A, 2 = B, 3 = C, dst)
const ruangNumber = parseInt(ruang.nomorRuang) || 1;
const ruangLetter = String.fromCharCode(64 + ruangNumber); // 64 = '@', 65 = 'A', 66 = 'B', dst
// 3. Hitung nomor antrian ruang (dimulai dari 1, maksimal 3 digit)
const roomQueues = allPatients.value.filter(p =>
p.kodeKlinik === klinikRuang.kodeKlinik &&
p.nomorRuang === ruang.nomorRuang &&
p.processStage === 'klinik-ruang'
);
const queueNumber = roomQueues.length + 1;
const queueNumberStr = String(queueNumber).padStart(3, "0");
// 4. Format nomor antrian: AA001, AB002, dst
const newNoAntrian = `${firstLetter}${ruangLetter}${queueNumberStr}`;
// Use API ticket number if available, otherwise generate locally
if (apiTicketNumber) {
newNoAntrian = apiTicketNumber; // Use ticket from API (e.g., "PK001")
console.log('🎫 Using API ticket number:', newNoAntrian);
} else {
// 1. Ambil huruf pertama dari nama klinik/poli
const firstLetter = klinikRuang.namaKlinik.charAt(0).toUpperCase();
// 2. Konversi nomor ruang ke abjad (1 = A, 2 = B, 3 = C, dst)
const ruangNumber = parseInt(ruang.nomorRuang) || 1;
const ruangLetter = String.fromCharCode(64 + ruangNumber); // 64 = '@', 65 = 'A', 66 = 'B', dst
// 3. Hitung nomor antrian ruang (dimulai dari 1, maksimal 3 digit)
const roomQueues = allPatients.value.filter(p =>
p.kodeKlinik === klinikRuang.kodeKlinik &&
p.nomorRuang === ruang.nomorRuang &&
p.processStage === 'klinik-ruang'
);
const queueNumber = roomQueues.length + 1;
const queueNumberStr = String(queueNumber).padStart(3, "0");
// 4. Format nomor antrian: AA001, AB002, dst
newNoAntrian = `${firstLetter}${ruangLetter}${queueNumberStr}`;
}
const newPatient = {
no: newNo,
@@ -1475,7 +1517,6 @@ 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" };