// server/api/queue/patients.ts // Contoh implementasi API endpoints untuk antrian pasien // NOTE: Ini adalah contoh - sesuaikan dengan database dan framework yang digunakan import type { H3Event } from 'h3' // Mock database (ganti dengan database real) const mockDB: any[] = [] interface Patient { no: number jamPanggil: string barcode: string noAntrian: string shift: string klinik: string fastTrack: string pembayaran: string status: string processStage: string createdAt: string registrationType?: string visitType?: string visitDate?: string } // GET /api/queue/patients - Get all patients export default defineEventHandler(async (event: H3Event) => { try { // TODO: Replace with actual database query // const patients = await db.query('SELECT * FROM patients ORDER BY created_at DESC') // Mock response const patients = mockDB return { success: true, data: patients, message: 'Patients fetched successfully', } } catch (error: any) { throw createError({ statusCode: 500, message: error.message || 'Failed to fetch patients', }) } }) // GET /api/queue/patients/:id - Get single patient export default defineEventHandler(async (event: H3Event) => { const idOrBarcode = getRouterParam(event, 'id') try { // TODO: Replace with actual database query // const patient = await db.query('SELECT * FROM patients WHERE barcode = ? OR id = ?', [idOrBarcode, idOrBarcode]) const patient = mockDB.find( (p: Patient) => p.barcode === idOrBarcode || p.no.toString() === idOrBarcode ) if (!patient) { throw createError({ statusCode: 404, message: 'Patient not found', }) } return { success: true, data: patient, } } catch (error: any) { if (error.statusCode) throw error throw createError({ statusCode: 500, message: error.message || 'Failed to fetch patient', }) } }) // POST /api/queue/patients - Create new patient export default defineEventHandler(async (event: H3Event) => { const body = await readBody(event) try { // Validate required fields if (!body.clinic || !body.paymentType) { throw createError({ statusCode: 400, message: 'Missing required fields: clinic, paymentType', }) } // Helper function untuk generate barcode dengan format: YYMMDD + 5 digit sequential // Format: YY (tahun 2 digit terakhir) + MM (bulan 2 digit) + DD (tanggal 2 digit) + XXXXX (5 digit sequential) // Contoh: 26011400001, 26011400002, dst // Counter akan reset setiap ganti tanggal (mulai dari 00001 lagi) const generateBarcode = () => { const now = new Date(); const year = String(now.getFullYear()).slice(-2); // 2 digit tahun terakhir const month = String(now.getMonth() + 1).padStart(2, '0'); // 2 digit bulan const day = String(now.getDate()).padStart(2, '0'); // 2 digit tanggal const datePrefix = `${year}${month}${day}`; // YYMMDD // Gunakan counter berdasarkan existing patients untuk sequential // NOTE: Di production, gunakan database counter atau shared counter service const existingCount = mockDB.filter(p => p.barcode && p.barcode.startsWith(datePrefix)).length; const counter = existingCount + 1; const counterCode = String(counter).padStart(5, '0'); // 5 digit sequential return `${datePrefix}${counterCode}`; }; // Generate patient data const barcode = generateBarcode(); const newPatient: Patient = { no: mockDB.length + 1, jamPanggil: new Date().toLocaleTimeString('id-ID', { hour: '2-digit', minute: '2-digit' }), barcode: barcode, noAntrian: `UM${String(mockDB.length + 1).padStart(4, '0')} | Onsite - ${barcode}`, shift: body.shift || 'Shift 1', klinik: body.clinic, fastTrack: 'TIDAK', pembayaran: body.paymentType, status: body.visitType === 'SEKARANG' ? 'waiting' : 'pending', processStage: 'loket', createdAt: new Date().toISOString(), registrationType: 'onsite', visitType: body.visitType || 'SEKARANG', visitDate: body.visitDate || new Date().toISOString().substring(0, 10), } // TODO: Insert to database // await db.query('INSERT INTO patients SET ?', newPatient) mockDB.push(newPatient) return { success: true, data: newPatient, message: 'Patient created successfully', } } catch (error: any) { if (error.statusCode) throw error throw createError({ statusCode: 500, message: error.message || 'Failed to create patient', }) } }) // PATCH /api/queue/patients/:id - Update patient export default defineEventHandler(async (event: H3Event) => { const idOrBarcode = getRouterParam(event, 'id') const body = await readBody(event) try { // TODO: Replace with actual database query // const patient = await db.query('SELECT * FROM patients WHERE barcode = ? OR id = ?', [idOrBarcode, idOrBarcode]) const patientIndex = mockDB.findIndex( (p: Patient) => p.barcode === idOrBarcode || p.no.toString() === idOrBarcode ) if (patientIndex === -1) { throw createError({ statusCode: 404, message: 'Patient not found', }) } // Update patient const updatedPatient = { ...mockDB[patientIndex], ...body, updatedAt: new Date().toISOString(), } // TODO: Update in database // await db.query('UPDATE patients SET ? WHERE barcode = ?', [body, idOrBarcode]) mockDB[patientIndex] = updatedPatient return { success: true, data: updatedPatient, message: 'Patient updated successfully', } } catch (error: any) { if (error.statusCode) throw error throw createError({ statusCode: 500, message: error.message || 'Failed to update patient', }) } }) // POST /api/queue/patients/batch - Batch sync export default defineEventHandler(async (event: H3Event) => { const body = await readBody(event) const { patients } = body try { if (!Array.isArray(patients)) { throw createError({ statusCode: 400, message: 'patients must be an array', }) } // TODO: Batch insert/update to database // await db.query('INSERT INTO patients VALUES ? ON DUPLICATE KEY UPDATE ...', [patients]) patients.forEach((patient: Patient) => { const index = mockDB.findIndex((p: Patient) => p.barcode === patient.barcode) if (index === -1) { mockDB.push(patient) } else { mockDB[index] = patient } }) return { success: true, message: `Synced ${patients.length} patients`, } } catch (error: any) { if (error.statusCode) throw error throw createError({ statusCode: 500, message: error.message || 'Failed to batch sync', }) } })