feat(encounter): implement encounter detail loading and update handling in entry form

This commit is contained in:
riefive
2025-11-10 12:44:27 +07:00
parent a8bc3647a1
commit b52f438b23
6 changed files with 404 additions and 36 deletions

No files matched your search

+158 -7
View File
@@ -18,7 +18,7 @@ import {
getValueTreeItems as getSpecialistTreeItems,
} from '~/services/specialist.service'
import { getValueLabelList as getDoctorValueLabelList } from '~/services/doctor.service'
import { create as createEncounter } from '~/services/encounter.service'
import { create as createEncounter, getDetail as getEncounterDetail, update as updateEncounter } from '~/services/encounter.service'
// Handlers
import {
@@ -55,11 +55,17 @@ const specialistsData = ref<any[]>([]) // Store full specialist data with id
const doctorsList = ref<Array<{ value: string; label: string }>>([])
const recSelectId = ref<number | null>(null)
const isSaving = ref(false)
const isLoadingDetail = ref(false)
const formRef = ref<InstanceType<typeof AppEncounterEntryForm> | null>(null)
const encounterData = ref<any>(null)
const formObjects = ref<any>({})
// Computed for edit mode
const isEditMode = computed(() => props.id > 0)
// Computed for save button disable state
const isSaveDisabled = computed(() => {
return !selectedPatient.value || !selectedPatientObject.value || isSaving.value
return !selectedPatient.value || !selectedPatientObject.value || isSaving.value || isLoadingDetail.value
})
function getListPath(): string {
@@ -186,19 +192,24 @@ async function handleSaveEncounter(formValues: any) {
payload.allocatedVisitCount = 0
}
// Call encounter service
const result = await createEncounter(payload)
// Call encounter service - use update if edit mode, create otherwise
let result
if (isEditMode.value) {
result = await updateEncounter(props.id, payload)
} else {
result = await createEncounter(payload)
}
if (result.success) {
toast({
title: 'Berhasil',
description: 'Kunjungan berhasil dibuat',
description: isEditMode.value ? 'Kunjungan berhasil diperbarui' : 'Kunjungan berhasil dibuat',
variant: 'default',
})
// Redirect to list page
await navigateTo(getListPath())
} else {
const errorMessage = result.body?.message || 'Gagal membuat kunjungan'
const errorMessage = result.body?.message || (isEditMode.value ? 'Gagal memperbarui kunjungan' : 'Gagal membuat kunjungan')
toast({
title: 'Gagal',
description: errorMessage,
@@ -209,7 +220,7 @@ async function handleSaveEncounter(formValues: any) {
console.error('Error saving encounter:', error)
toast({
title: 'Gagal',
description: error?.message || 'Gagal membuat kunjungan',
description: error?.message || (isEditMode.value ? 'Gagal memperbarui kunjungan' : 'Gagal membuat kunjungan'),
variant: 'destructive',
})
} finally {
@@ -370,11 +381,149 @@ async function handleInit() {
await handleFetchSpecialists()
}
/**
* Load encounter detail data for edit mode
*/
async function loadEncounterDetail() {
if (!isEditMode.value || props.id <= 0) {
return
}
try {
isLoadingDetail.value = true
const result = await getEncounterDetail(props.id, {
includes: 'patient,patient-person,specialist,subspecialist,appointment_doctor,responsible_doctor,encounter_payments',
})
if (result.success && result.body?.data) {
encounterData.value = result.body.data
await mapEncounterToForm(encounterData.value)
} else {
toast({
title: 'Gagal',
description: 'Gagal memuat data kunjungan',
variant: 'destructive',
})
// Redirect to list page if encounter not found
await navigateTo(getListPath())
}
} catch (error: any) {
console.error('Error loading encounter detail:', error)
toast({
title: 'Gagal',
description: error?.message || 'Gagal memuat data kunjungan',
variant: 'destructive',
})
// Redirect to list page on error
await navigateTo(getListPath())
} finally {
isLoadingDetail.value = false
}
}
/**
* Map encounter data to form fields
*/
async function mapEncounterToForm(encounter: any) {
if (!encounter) return
// Set patient data and wait for it to load
if (encounter.patient) {
selectedPatient.value = String(encounter.patient.id)
selectedPatientObject.value = encounter.patient
// Fetch full patient data to ensure we have all fields
await getPatientCurrent(selectedPatient.value)
}
// Map form fields
const formData: any = {}
// Patient data (readonly, populated from selected patient)
// Use selectedPatientObject which now has full patient data
if (selectedPatientObject.value?.person) {
formData.patientName = selectedPatientObject.value.person.name || ''
formData.nationalIdentity = selectedPatientObject.value.person.residentIdentityNumber || ''
formData.medicalRecordNumber = selectedPatientObject.value.number || ''
} else if (encounter.patient?.person) {
// Fallback to encounter patient data if selectedPatientObject is not yet loaded
formData.patientName = encounter.patient.person.name || ''
formData.nationalIdentity = encounter.patient.person.residentIdentityNumber || ''
formData.medicalRecordNumber = encounter.patient.number || ''
}
// Doctor ID
const doctorId = encounter.appointment_doctor_id || encounter.responsible_doctor_id
if (doctorId) {
formData.doctorId = String(doctorId)
}
// Specialist/Subspecialist
if (encounter.subspecialist?.code) {
formData.subSpecialistId = encounter.subspecialist.code
} else if (encounter.specialist?.code) {
formData.subSpecialistId = encounter.specialist.code
}
// Register date
if (encounter.registeredAt) {
// Convert ISO date to local date string (YYYY-MM-DD)
const date = new Date(encounter.registeredAt)
formData.registerDate = date.toISOString().split('T')[0]
} else if (encounter.visitDate) {
const date = new Date(encounter.visitDate)
formData.registerDate = date.toISOString().split('T')[0]
}
// Payment data
// Check if encounter has payment data
if (encounter.encounter_payments && Array.isArray(encounter.encounter_payments) && encounter.encounter_payments.length > 0) {
const payment = encounter.encounter_payments[0]
// Determine payment type from paymentMethod_code
if (payment.paymentMethod_code === 'insurance') {
// Check if it's JKN or JKMM based on member_number or other indicators
// For now, default to 'jkn' - this might need adjustment based on actual data structure
formData.paymentType = 'jkn'
formData.cardNumber = payment.member_number || ''
formData.sepNumber = payment.ref_number || ''
// Note: patientCategory and sepType might need to be extracted from other sources
// as they might not be directly in the payment object
} else {
// For non-insurance payments, try to determine from encounter data
// This might need adjustment based on actual API response
formData.paymentType = 'spm' // default to SPM
}
} else {
// Fallback: try to get payment type from encounter.paymentType if available
if (encounter.paymentType) {
formData.paymentType = encounter.paymentType
}
if (encounter.cardNumber) {
formData.cardNumber = encounter.cardNumber
}
if (encounter.ref_number || encounter.sepNumber) {
formData.sepNumber = encounter.ref_number || encounter.sepNumber
}
}
// Set form objects for the form component
formObjects.value = formData
// Fetch doctors based on specialist/subspecialist selection
if (formData.subSpecialistId) {
await handleFetchDoctors(formData.subSpecialistId)
}
}
provide('rec_select_id', recSelectId)
provide('table_data_loader', isLoading)
onMounted(async () => {
await handleInit()
// Load encounter detail if in edit mode
if (isEditMode.value) {
await loadEncounterDetail()
}
})
</script>
@@ -396,6 +545,8 @@ onMounted(async () => {
:specialists="specialistsTree"
:doctor="doctorsList"
:patient="selectedPatientObject"
:objects="formObjects"
:is-loading="isLoadingDetail"
@event="handleEvent"
@fetch="handleFetch"
/>