Files
simrsx-fe/app/components/content/encounter/entry.vue
T
2025-10-28 10:42:29 +07:00

213 lines
6.1 KiB
Vue

<script setup lang="ts">
// Components
import AppEncounterEntryForm from '~/components/app/encounter/entry-form.vue'
import AppViewPatient from '~/components/app/patient/view-patient.vue'
// Types
import type { DataTableLoader } from '~/components/pub/my-ui/data-table/type'
import type { TreeItem } from '~/components/pub/my-ui/select-tree/type'
// Constants
import { paymentTypes, sepRefTypeCodes, participantGroups } from '~/lib/constants.vclaim'
// Services
import {
getList as getSpecialistList,
getValueTreeItems as getSpecialistTreeItems,
} from '~/services/specialist.service'
import { getValueLabelList as getDoctorValueLabelList } from '~/services/doctor.service'
// Handlers
import {
patients,
selectedPatient,
selectedPatientObject,
paginationMeta,
getPatientsList,
getPatientCurrent,
getPatientByIdentifierSearch,
} from '~/handlers/patient.handler'
const props = defineProps<{
id: number
formType: string
}>()
const openPatient = ref(false)
const isLoading = reactive<DataTableLoader>({
isTableLoading: false,
})
const paymentsList = ref<Array<{ value: string; label: string }>>([])
const sepsList = ref<Array<{ value: string; label: string }>>([])
const participantGroupsList = ref<Array<{ value: string; label: string }>>([])
const specialistsTree = ref<TreeItem[]>([])
const doctorsList = ref<Array<{ value: string; label: string }>>([])
function handleSavePatient() {
selectedPatientObject.value = null
setTimeout(() => {
getPatientCurrent(selectedPatient.value)
}, 150)
}
function toKebabCase(str: string): string {
return str.replace(/([A-Z])/g, '-$1').toLowerCase()
}
function toNavigateSep(values: any) {
const queryParams = new URLSearchParams()
Object.keys(values).forEach((field) => {
if (values[field]) {
queryParams.append(toKebabCase(field), values[field])
}
})
navigateTo('/integration/bpjs/sep/add' + `?${queryParams.toString()}`)
}
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') {
console.log('formValues', value)
toNavigateSep({ resource: 'encounter', isService: 'false', ...value })
} else if (menu === 'save') {
console.log('Save encounter:', value)
} else if (menu === 'cancel') {
console.log('Cancel')
}
}
async function handleFetchSpecialists() {
try {
const specialistsResult = await getSpecialistList({ 'page-size': 100, includes: 'subspecialists' })
if (specialistsResult.success) {
const specialists = specialistsResult.body?.data || []
specialistsTree.value = getSpecialistTreeItems(specialists)
}
} catch (error) {
console.error('Error fetching specialist-subspecialist tree:', error)
}
}
/**
* Helper function to check if a value exists in the specialistsTree
* Returns true if it's a leaf node (subspecialist), false if parent node (specialist)
*/
function isSubspecialist(value: string, items: TreeItem[]): boolean {
for (const item of items) {
if (item.value === value) {
// If this item has children, it's not selected, so skip
// If this is the selected item, check if it has children in the tree
return false // This means it's a specialist, not a subspecialist
}
if (item.children) {
for (const child of item.children) {
if (child.value === value) {
// This is a subspecialist (leaf node)
return true
}
}
}
}
return false
}
async function handleFetchDoctors(subSpecialistId: string) {
try {
// Check if the selected value is a subspecialist or specialist
const isSub = isSubspecialist(subSpecialistId, specialistsTree.value)
// Build filter based on selection type
const filterParams: any = { 'page-size': 100, includes: 'employee-Person' }
if (isSub) {
// If selected is subspecialist, filter by subspecialist-id
filterParams['subspecialist-id'] = subSpecialistId
} else {
// If selected is specialist, filter by specialist-id
filterParams['specialist-id'] = subSpecialistId
}
const doctors = await getDoctorValueLabelList(filterParams)
doctorsList.value = doctors
} catch (error) {
console.error('Error fetching doctors:', error)
doctorsList.value = []
}
}
function handleFetch(value?: any) {
if (value?.subSpecialistId) {
handleFetchDoctors(value.subSpecialistId)
}
}
async function handleInit() {
paymentsList.value = Object.keys(paymentTypes).map((item) => ({
value: item.toString(),
label: paymentTypes[item],
})) as any
sepsList.value = Object.keys(sepRefTypeCodes).map((item) => ({
value: item.toString(),
label: sepRefTypeCodes[item],
})) as any
participantGroupsList.value = Object.keys(participantGroups).map((item) => ({
value: item.toString(),
label: participantGroups[item],
})) as any
// Fetch tree data
await handleFetchSpecialists()
}
provide('table_data_loader', isLoading)
onMounted(async () => {
await handleInit()
})
</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 }}</span>
Kunjungan
</div>
<AppEncounterEntryForm
:payments="paymentsList"
:seps="sepsList"
:participant-groups="participantGroupsList"
:specialists="specialistsTree"
:doctor="doctorsList"
:patient="selectedPatientObject"
@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"
/>
</template>