From d2ceda37bf0e9b76cefb4aa26112bafb17abeace Mon Sep 17 00:00:00 2001 From: riefive Date: Thu, 4 Dec 2025 10:58:16 +0700 Subject: [PATCH] feat: Implement encounter list management with search, date range filtering, and record actions. --- app/components/app/encounter/filter-nav.vue | 80 +++++++++++---------- app/components/content/encounter/list.vue | 68 +++++++++++------- app/handlers/encounter-entry.handler.ts | 2 +- 3 files changed, 89 insertions(+), 61 deletions(-) diff --git a/app/components/app/encounter/filter-nav.vue b/app/components/app/encounter/filter-nav.vue index 947148aa..8f4c850e 100644 --- a/app/components/app/encounter/filter-nav.vue +++ b/app/components/app/encounter/filter-nav.vue @@ -18,25 +18,13 @@ const props = defineProps<{ onExportCsv?: () => void }>() -// function emitSearchNavClick() { -// props.refSearchNav?.onClick() -// } -// -// function onInput(event: Event) { -// props.refSearchNav?.onInput((event.target as HTMLInputElement).value) -// } -// -// function btnClick() { -// props.prep?.addNav?.onClick?.() -// } +const emit = defineEmits<{ + apply: [filters: { personName: string; startDate: string; endDate: string }] +}>() const searchQuery = ref('') const isRoleRegistration = props.activePositon === 'registration' const isRoleMedical = props.activePositon === 'medical' -const dateRange = ref<{ from: Date | null; to: Date | null }>({ - from: new Date(), - to: new Date(), -}) const df = new DateFormatter('en-US', { dateStyle: 'medium', @@ -49,31 +37,47 @@ const todayCalendar = new CalendarDate(today.getFullYear(), today.getMonth() + 1 // Get date 1 month ago const oneMonthAgo = new Date(today) oneMonthAgo.setMonth(today.getMonth() - 1) -const oneMonthAgoCalendar = new CalendarDate(oneMonthAgo.getFullYear(), oneMonthAgo.getMonth() + 1, oneMonthAgo.getDate()) +const oneMonthAgoCalendar = new CalendarDate( + oneMonthAgo.getFullYear(), + oneMonthAgo.getMonth() + 1, + oneMonthAgo.getDate(), +) const value = ref({ start: oneMonthAgoCalendar, end: todayCalendar, }) as Ref -// function onFilterClick() { -// console.log('Search:', searchQuery.value) -// console.log('Date Range:', dateRange.value) -// props.refSearchNav?.onClick() -// } +function onFilterClick() { + const startDate = value.value.start ? value.value.start.toString() : '' + const endDate = value.value.end ? value.value.end.toString() : startDate + + emit('apply', { + personName: searchQuery.value, + startDate, + endDate, + }) +} - + @@ -99,28 +103,32 @@ const value = ref({ - - - - Ekspor PDF - - - Ekspor CSV - - - Ekspor Excel - + Ekspor PDF + Ekspor CSV + Ekspor Excel diff --git a/app/components/content/encounter/list.vue b/app/components/content/encounter/list.vue index 1ea0d6a0..3aeb1254 100644 --- a/app/components/content/encounter/list.vue +++ b/app/components/content/encounter/list.vue @@ -13,7 +13,11 @@ import { useSidebar } from '~/components/pub/ui/sidebar/utils' import { getServicePosition } from '~/lib/roles' // previously getPositionAs // Services -import { getList as getEncounterList, remove as removeEncounter, cancel as cancelEncounter } from '~/services/encounter.service' +import { + getList as getEncounterList, + remove as removeEncounter, + cancel as cancelEncounter, +} from '~/services/encounter.service' // Apps import Content from '~/components/app/encounter/list.vue' @@ -40,6 +44,7 @@ const { getActiveRole } = useUserStore() // Main data const data = ref([]) const dataFiltered = ref([]) +const filterParams = ref({}) const activeServicePosition = ref(getServicePosition(getActiveRole())) const isLoading = reactive({ summary: false, @@ -99,27 +104,30 @@ provide('rec_action', recAction) provide('rec_item', recItem) provide('table_data_loader', isLoading) -watch(getActiveRole, (role? : string) => { +watch(getActiveRole, (role?: string) => { activeServicePosition.value = getServicePosition(role) }) -watch(() => recAction.value, () => { - const basePath = `/${props.classCode}/encounter` - if (recAction.value === ActionEvents.showConfirmDelete) { - isRecordConfirmationOpen.value = true - } else if (recAction.value === ActionEvents.showCancel) { - isRecordCancelOpen.value = true - } else if (recAction.value === ActionEvents.showDetail) { - navigateTo(`${basePath}/${recId.value}/detail`) - } else if (recAction.value === ActionEvents.showEdit) { - navigateTo(`${basePath}/${recId.value}/edit`) - } else if (recAction.value === ActionEvents.showProcess) { - navigateTo(`${basePath}/${recId.value}/process`) - } else if (recAction.value === ActionEvents.showConfirmDelete) { - isRecordConfirmationOpen.value = true - } - recAction.value = '' // reset -}) +watch( + () => recAction.value, + () => { + const basePath = `/${props.classCode}/encounter` + if (recAction.value === ActionEvents.showConfirmDelete) { + isRecordConfirmationOpen.value = true + } else if (recAction.value === ActionEvents.showCancel) { + isRecordCancelOpen.value = true + } else if (recAction.value === ActionEvents.showDetail) { + navigateTo(`${basePath}/${recId.value}/detail`) + } else if (recAction.value === ActionEvents.showEdit) { + navigateTo(`${basePath}/${recId.value}/edit`) + } else if (recAction.value === ActionEvents.showProcess) { + navigateTo(`${basePath}/${recId.value}/process`) + } else if (recAction.value === ActionEvents.showConfirmDelete) { + isRecordConfirmationOpen.value = true + } + recAction.value = '' // reset + }, +) onMounted(() => { getPatientList() @@ -128,13 +136,16 @@ onMounted(() => { /////// Functions async function getPatientList() { isLoading.isTableLoading = true + const includesParams = + 'patient,patient-person,patient-person-addresses,unit,Appointment_Doctor,Appointment_Doctor-employee,Appointment_Doctor-employee-person,Responsible_Doctor,Responsible_Doctor-employee,Responsible_Doctor-employee-person' + data.value = [] try { - const params: any = { includes: 'patient,patient-person' } + const params: any = { includes: includesParams, ...filterParams.value } if (props.classCode) { - params['class-code'] = props.classCode + params.class_code = props.classCode } if (props.subClassCode) { - params['sub-class-code'] = props.subClassCode + params.sub_class_code = props.subClassCode } const result = await getEncounterList(params) if (result.success) { @@ -148,6 +159,15 @@ async function getPatientList() { } } +function handleFilterApply(filters: { personName: string; startDate: string; endDate: string }) { + filterParams.value = { + 'person-name': filters.personName, + 'start-date': filters.startDate, + 'end-date': filters.endDate, + } + getPatientList() +} + // Handle confirmation result async function handleConfirmCancel(record: any, action: string) { if (action === 'deactivate' && record?.id) { @@ -243,7 +263,7 @@ function handleRemoveConfirmation() { - + diff --git a/app/handlers/encounter-entry.handler.ts b/app/handlers/encounter-entry.handler.ts index a7daf29d..2a91b1b1 100644 --- a/app/handlers/encounter-entry.handler.ts +++ b/app/handlers/encounter-entry.handler.ts @@ -519,7 +519,7 @@ export function useEncounterEntry(props: { const payload: any = { patient_id: patientId, - appointment_doctor_code: formValues.doctorId || null, + appointment_doctor_code: formValues.doctorCode || null, class_code: props.classCode || '', subClass_code: props.subClassCode || '', infra_id: formValues.infra_id ?? null,