From 99c5266f2b23e0a1ba4bac94963059142a7781da Mon Sep 17 00:00:00 2001 From: riefive Date: Tue, 28 Oct 2025 10:02:12 +0700 Subject: [PATCH] fix: add tree select subspecialist and filter doctor --- app/components/app/encounter/entry-form.vue | 62 +++++++++------ app/components/content/encounter/entry.vue | 83 +++++++++++++++++++++ app/models/specialist.ts | 2 + app/services/doctor.service.ts | 41 ++++++++++ app/services/specialist.service.ts | 18 +++++ 5 files changed, 183 insertions(+), 23 deletions(-) create mode 100644 app/services/doctor.service.ts diff --git a/app/components/app/encounter/entry-form.vue b/app/components/app/encounter/entry-form.vue index a66bfef7..446c9e17 100644 --- a/app/components/app/encounter/entry-form.vue +++ b/app/components/app/encounter/entry-form.vue @@ -9,10 +9,12 @@ import { Input } from '~/components/pub/ui/input' import Select from '~/components/pub/ui/select/Select.vue' import Combobox from '~/components/pub/my-ui/combobox/combobox.vue' import DatepickerSingle from '~/components/pub/my-ui/datepicker/datepicker-single.vue' +import TreeSelect from '~/components/pub/my-ui/select-tree/tree-select.vue' // Types import { IntegrationEncounterSchema, type IntegrationEncounterFormData } from '~/schemas/integration-encounter.schema' import type { PatientEntity } from '~/models/patient' +import type { TreeItem } from '~/components/pub/my-ui/select-tree/type' // Helpers import { toTypedSchema } from '@vee-validate/zod' @@ -23,6 +25,7 @@ const props = defineProps<{ isReadonly?: boolean doctor?: any[] subSpecialist?: any[] + specialists?: TreeItem[] payments: any[] participantGroups?: any[] seps: any[] @@ -60,18 +63,31 @@ const isReadonly = props.isReadonly !== undefined ? props.isReadonly : false const sepFileInput = ref(null) const sippFileInput = ref(null) -const doctorOpts = ref([ - { label: 'Pilih', value: '' }, - { label: 'Dr. A', value: '1' }, -]) - -const subSpecialistOpts = ref([ - { label: 'Pilih', value: '' }, - { label: 'Subspesialis A', value: '1' }, -]) +const doctorOpts = computed(() => { + // Add default option + const defaultOption = [{ label: 'Pilih', value: '' }] + // Add doctors from props + const doctors = props.doctor || [] + return [...defaultOption, ...doctors] +}) const isJKNPayment = computed(() => paymentType.value === 'jkn') +async function onFetchChildren(parentId: string): Promise { + console.log('onFetchChildren', parentId) +} + +// Watch specialist/subspecialist selection to fetch doctors +watch(subSpecialistId, async (newValue) => { + if (newValue) { + console.log('SubSpecialist changed:', newValue) + // Reset doctor selection + doctorId.value = '' + // Emit fetch event to parent + emit('fetch', { subSpecialistId: newValue }) + } +}) + // Sync props to form fields watch(props, (value) => { const patient = value.patient || ({} as PatientEntity) @@ -233,17 +249,17 @@ const onSubmit = handleSubmit((values) => { :cellFlex="false" > - + - @@ -364,7 +380,14 @@ const onSubmit = handleSubmit((values) => { /> + + - - diff --git a/app/components/content/encounter/entry.vue b/app/components/content/encounter/entry.vue index cc58dd57..5a3bd592 100644 --- a/app/components/content/encounter/entry.vue +++ b/app/components/content/encounter/entry.vue @@ -5,10 +5,18 @@ 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, @@ -32,6 +40,8 @@ const isLoading = reactive({ const paymentsList = ref>([]) const sepsList = ref>([]) const participantGroupsList = ref>([]) +const specialistsTree = ref([]) +const doctorsList = ref>([]) function handleSavePatient() { selectedPatientObject.value = null @@ -71,6 +81,74 @@ function handleEvent(menu: string, value?: any) { } } +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 } + + 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 + } + + console.log('Fetching doctors with filter:', filterParams) + + const doctors = await getDoctorValueLabelList(filterParams) + doctorsList.value = doctors + console.log('Fetched doctors:', 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(), @@ -84,6 +162,8 @@ async function handleInit() { value: item.toString(), label: participantGroups[item], })) as any + // Fetch tree data + await handleFetchSpecialists() } provide('table_data_loader', isLoading) @@ -107,8 +187,11 @@ onMounted(async () => { :payments="paymentsList" :seps="sepsList" :participant-groups="participantGroupsList" + :specialists="specialistsTree" + :doctor="doctorsList" :patient="selectedPatientObject" @event="handleEvent" + @fetch="handleFetch" /> { + let data: { value: string; label: string }[] = [] + const result = await getList(params) + if (result.success) { + const resultData = result.body?.data || [] + data = resultData.map((item: Doctor) => ({ + value: item.id ? Number(item.id) : item.id, + label: item.employee?.person?.name || '', + })) + } + return data +} diff --git a/app/services/specialist.service.ts b/app/services/specialist.service.ts index c2c34e3f..293ce6ab 100644 --- a/app/services/specialist.service.ts +++ b/app/services/specialist.service.ts @@ -3,6 +3,7 @@ import * as base from './_crud-base' // Types import type { Specialist } from '~/models/specialist' +import type { TreeItem } from '~/models/_base' const path = '/api/v1/specialist' const name = 'specialist' @@ -40,3 +41,20 @@ export async function getValueLabelList(params: any = null): Promise<{ value: st } return data } + +/** + * Convert specialist response to TreeItem[] with subspecialist children + * @param specialists Array of specialist objects from API + * @returns TreeItem[] + */ +export function getValueTreeItems(specialists: any[]): TreeItem[] { + return specialists.map((specialist: Specialist) => ({ + value: specialist.id ? String(specialist.id) : specialist.code, + label: specialist.name, + hasChildren: Array.isArray(specialist.subspecialists) && specialist.subspecialists.length > 0, + children: + Array.isArray(specialist.subspecialists) && specialist.subspecialists.length > 0 + ? getValueTreeItems(specialist.subspecialists) + : undefined, + })) +}