242 lines
6.1 KiB
Vue
242 lines
6.1 KiB
Vue
<script setup lang="ts">
|
|
// Components
|
|
import { Button } from '~/components/pub/ui/button'
|
|
import AppEncounterEntryForm from '~/components/app/encounter/entry-form.vue'
|
|
import AppViewPatient from '~/components/app/patient/view-patient.vue'
|
|
import AppViewHistory from '~/components/app/sep/view-history.vue'
|
|
|
|
// Helpers
|
|
import { refDebounced } from '@vueuse/core'
|
|
|
|
// Handlers
|
|
import { useEncounterEntry } from '~/handlers/encounter-entry.handler'
|
|
import { useIntegrationSepEntry } from '~/handlers/integration-sep-entry.handler'
|
|
|
|
// Props
|
|
const props = defineProps<{
|
|
id: number
|
|
classCode?: 'ambulatory' | 'emergency' | 'inpatient' | 'outpatient'
|
|
subClassCode?: 'reg' | 'rehab' | 'chemo' | 'emg' | 'eon' | 'op' | 'icu' | 'hcu' | 'vk'
|
|
formType: string
|
|
}>()
|
|
|
|
const route = useRoute()
|
|
const formRef = ref<InstanceType<typeof AppEncounterEntryForm> | null>(null)
|
|
|
|
const {
|
|
paymentsList,
|
|
sepNumber,
|
|
sepsList,
|
|
participantGroupsList,
|
|
specialistsTree,
|
|
doctorsList,
|
|
recSelectId,
|
|
isLoadingDetail,
|
|
formObjects,
|
|
openPatient,
|
|
isMemberValid,
|
|
isSepValid,
|
|
isCheckingSep,
|
|
isSaveDisabled,
|
|
isLoading,
|
|
patients,
|
|
selectedDoctor,
|
|
selectedPatient,
|
|
selectedPatientObject,
|
|
paginationMeta,
|
|
toNavigateSep,
|
|
getListPath,
|
|
handleInit,
|
|
getFetchEncounterDetail,
|
|
handleSaveEncounter,
|
|
getPatientsList,
|
|
getPatientCurrent,
|
|
getPatientByIdentifierSearch,
|
|
// getIsSubspecialist,
|
|
getDoctorInfo,
|
|
getValidateMember,
|
|
getValidateSepNumber,
|
|
handleFetchDoctors,
|
|
} = useEncounterEntry(props)
|
|
const { recSepId, openHistory, histories, getMonitoringHistoryMappers } = useIntegrationSepEntry()
|
|
|
|
const debouncedSepNumber = refDebounced(sepNumber, 500)
|
|
|
|
///// Functions
|
|
function handleSavePatient() {
|
|
selectedPatientObject.value = null
|
|
setTimeout(() => {
|
|
getPatientCurrent(selectedPatient.value)
|
|
}, 150)
|
|
}
|
|
|
|
function handleSaveClick() {
|
|
if (formRef.value && typeof formRef.value.submitForm === 'function') {
|
|
formRef.value.submitForm()
|
|
}
|
|
}
|
|
|
|
function handleFetch(value?: any) {
|
|
if (value?.subSpecialistId) {
|
|
handleFetchDoctors(value.subSpecialistId)
|
|
}
|
|
}
|
|
|
|
async function handleEvent(menu: string, value?: any) {
|
|
if (menu === 'search') {
|
|
getPatientsList({ 'page-size': 10, includes: 'person' }).then(() => {
|
|
openPatient.value = true
|
|
})
|
|
} else if (menu === 'add') {
|
|
navigateTo('/client/patient/add')
|
|
} else if (menu === 'add-sep') {
|
|
if (isSepValid.value) {
|
|
return
|
|
}
|
|
toNavigateSep({
|
|
isService: 'false',
|
|
encounterId: props.id || null,
|
|
sourcePath: route.path,
|
|
resource: `${props.classCode}-${props.subClassCode}`,
|
|
...value,
|
|
})
|
|
} else if (menu === 'sep-number-changed') {
|
|
const sepNumberText = String(value || '').trim()
|
|
if (sepNumberText.length > 5) {
|
|
await getValidateSepNumber(sepNumberText)
|
|
}
|
|
} else if (menu === 'member-changed') {
|
|
const memberText = String(value || '').trim()
|
|
if (memberText.length > 5) {
|
|
await getValidateMember(memberText)
|
|
}
|
|
} else if (menu === 'search-sep') {
|
|
const memberText = String(value?.cardNumber || '').trim()
|
|
if (memberText.length < 5) return
|
|
getMonitoringHistoryMappers(memberText).then(() => {
|
|
openHistory.value = true
|
|
})
|
|
return
|
|
} else if (menu === 'save') {
|
|
await handleSaveEncounter(value)
|
|
} else if (menu === 'cancel') {
|
|
navigateTo(getListPath())
|
|
}
|
|
}
|
|
|
|
provide('rec_select_id', recSelectId)
|
|
provide('rec_sep_id', recSepId)
|
|
provide('table_data_loader', isLoading)
|
|
|
|
watch(debouncedSepNumber, async (newValue) => {
|
|
await getValidateSepNumber(newValue)
|
|
})
|
|
|
|
watch(
|
|
() => formObjects.value?.paymentType,
|
|
(newValue) => {
|
|
isSepValid.value = false
|
|
if (newValue !== 'jkn') {
|
|
sepNumber.value = ''
|
|
}
|
|
},
|
|
)
|
|
|
|
watch(
|
|
() => props.id,
|
|
async (newId) => {
|
|
if (props.formType === 'edit' && newId > 0) {
|
|
await getFetchEncounterDetail()
|
|
}
|
|
},
|
|
)
|
|
|
|
onMounted(async () => {
|
|
await handleInit()
|
|
if (props.formType === 'edit' && props.id > 0) {
|
|
await getFetchEncounterDetail()
|
|
}
|
|
})
|
|
</script>
|
|
|
|
<template>
|
|
<div class="mb-5 border-b border-b-slate-300 pb-3 text-lg xl:text-xl">
|
|
<Icon
|
|
name="i-lucide-user"
|
|
class="me-2"
|
|
/>
|
|
<span class="font-semibold">{{ props.formType === 'add' ? 'Tambah' : 'Ubah' }}</span>
|
|
Kunjungan
|
|
</div>
|
|
|
|
<AppEncounterEntryForm
|
|
ref="formRef"
|
|
:mode="props.formType"
|
|
:is-loading="isLoadingDetail"
|
|
:is-member-valid="isMemberValid"
|
|
:is-sep-valid="isSepValid"
|
|
:is-checking-sep="isCheckingSep"
|
|
:payments="paymentsList"
|
|
:seps="sepsList"
|
|
:participant-groups="participantGroupsList"
|
|
:specialists="specialistsTree"
|
|
:doctorItems="doctorsList"
|
|
:selectedDoctor="selectedDoctor"
|
|
:patient="selectedPatientObject"
|
|
:objects="formObjects"
|
|
@on-select-doctor="getDoctorInfo"
|
|
@event="handleEvent"
|
|
@fetch="handleFetch"
|
|
/>
|
|
<AppViewPatient
|
|
v-model:open="openPatient"
|
|
v-model:selected="selectedPatient"
|
|
:patients="patients"
|
|
:pagination-meta="paginationMeta"
|
|
@fetch="
|
|
(value) => {
|
|
if (value.search && value.search.length >= 3) {
|
|
// Use identifier search for specific searches (NIK, RM, etc.)
|
|
getPatientByIdentifierSearch(value.search)
|
|
} else {
|
|
// Use regular search for general searches
|
|
getPatientsList({ ...value, 'page-size': 10, includes: 'person' })
|
|
}
|
|
}
|
|
"
|
|
@save="handleSavePatient"
|
|
/>
|
|
<AppViewHistory
|
|
v-model:open="openHistory"
|
|
:is-action="true"
|
|
:histories="histories"
|
|
/>
|
|
<!-- Footer Actions -->
|
|
<div class="mt-6 flex justify-end gap-2 border-t border-t-slate-300 pt-4">
|
|
<Button
|
|
variant="outline"
|
|
type="button"
|
|
class="h-[40px] min-w-[120px] rounded-md border-orange-400 text-orange-400 hover:bg-green-50 hover:text-orange-400"
|
|
@click="handleEvent('cancel')"
|
|
>
|
|
<Icon
|
|
name="i-lucide-x"
|
|
class="h-5 w-5"
|
|
/>
|
|
Batal
|
|
</Button>
|
|
<Button
|
|
type="button"
|
|
class="h-[40px] min-w-[120px] text-white"
|
|
:disabled="isSaveDisabled"
|
|
@click="handleSaveClick"
|
|
>
|
|
<Icon
|
|
name="i-lucide-save"
|
|
class="h-5 w-5"
|
|
/>
|
|
Simpan
|
|
</Button>
|
|
</div>
|
|
</template>
|