feat: implement SEP search functionality and enhance history management
This commit is contained in:
@@ -183,6 +183,10 @@ function onAddSep() {
|
||||
emit('event', 'add-sep', formValues)
|
||||
}
|
||||
|
||||
function onSearchSep() {
|
||||
emit('event', 'search-sep', { cardNumber: cardNumber.value })
|
||||
}
|
||||
|
||||
// Submit handler
|
||||
const onSubmit = handleSubmit((values) => {
|
||||
console.log('✅ Validated form values:', JSON.stringify(values, null, 2))
|
||||
@@ -193,23 +197,11 @@ const onSubmit = handleSubmit((values) => {
|
||||
const formRef = ref<HTMLFormElement | null>(null)
|
||||
|
||||
function submitForm() {
|
||||
console.log('🔵 submitForm called, formRef:', formRef.value)
|
||||
console.log('🔵 Form values:', {
|
||||
doctorId: doctorId.value,
|
||||
subSpecialistId: subSpecialistId.value,
|
||||
registerDate: registerDate.value,
|
||||
paymentType: paymentType.value,
|
||||
})
|
||||
console.log('🔵 Form errors:', errors.value)
|
||||
console.log('🔵 Form meta:', meta.value)
|
||||
|
||||
// Trigger form submit using native form submit
|
||||
// This will trigger validation and onSubmit handler
|
||||
if (formRef.value) {
|
||||
console.log('🔵 Calling formRef.value.requestSubmit()')
|
||||
formRef.value.requestSubmit()
|
||||
} else {
|
||||
console.warn('⚠️ formRef.value is null, cannot submit form')
|
||||
// Fallback: directly call onSubmit handler
|
||||
// Create a mock event object
|
||||
const mockEvent = {
|
||||
@@ -218,7 +210,6 @@ function submitForm() {
|
||||
} as SubmitEvent
|
||||
|
||||
// Call onSubmit directly
|
||||
console.log('🔵 Calling onSubmit with mock event')
|
||||
onSubmit(mockEvent)
|
||||
}
|
||||
}
|
||||
@@ -498,7 +489,7 @@ defineExpose({
|
||||
v-bind="sepNumberAttrs"
|
||||
placeholder="Tambah SEP terlebih dahulu"
|
||||
class="flex-1"
|
||||
:disabled="isLoading || isReadonly"
|
||||
:disabled="isLoading || isReadonly || isSepValid"
|
||||
/>
|
||||
<Button
|
||||
v-if="!isSepValid"
|
||||
@@ -521,11 +512,12 @@ defineExpose({
|
||||
/>
|
||||
</Button>
|
||||
<Button
|
||||
v-if="!isSepValid"
|
||||
v-if="isMemberValid"
|
||||
variant="outline"
|
||||
type="button"
|
||||
class="bg-primary"
|
||||
size="sm"
|
||||
@click="onSearchSep"
|
||||
>
|
||||
<Icon
|
||||
name="i-lucide-search"
|
||||
@@ -632,7 +624,7 @@ defineExpose({
|
||||
:colCount="3"
|
||||
:cellFlex="false"
|
||||
>
|
||||
<Cell>
|
||||
<Cell :col-span="2">
|
||||
<Label height="compact">Diagnosis</Label>
|
||||
<Field>
|
||||
<Input
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
<script lang="ts" setup>
|
||||
import { inject, type Ref } from 'vue'
|
||||
import { useRouter } from 'vue-router'
|
||||
// Components
|
||||
import { Button } from '~/components/pub/ui/button'
|
||||
|
||||
const props = defineProps<{
|
||||
rec: { sepNumber: string; }
|
||||
}>()
|
||||
|
||||
const router = useRouter()
|
||||
const record = props.rec || {}
|
||||
const recSepId = inject('rec_sep_id') as Ref<string>
|
||||
|
||||
function handleSelection() {
|
||||
recSepId.value = record.sepNumber || ''
|
||||
const pathUrl = `/integration/bpjs-vclaim/sep/${record.sepNumber || ''}/detail`
|
||||
router.push({ path: pathUrl })
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Button
|
||||
variant="outline"
|
||||
type="button"
|
||||
class="h-[40px] rounded-md border-orange-400 text-orange-400 hover:bg-green-50"
|
||||
@click="handleSelection"
|
||||
>
|
||||
Detail SEP
|
||||
</Button>
|
||||
</template>
|
||||
@@ -9,21 +9,25 @@ export interface SepHistoryData {
|
||||
careClass: string
|
||||
}
|
||||
|
||||
const ActionHistory = defineAsyncComponent(() => import('~/components/app/sep/action-history.vue'))
|
||||
|
||||
const keysDefault = ['sepNumber', 'sepDate', 'referralNumber', 'diagnosis', 'serviceType', 'careClass']
|
||||
const colsDefault = [{ width: 100 }, { width: 100 }, { width: 100 }, { width: 100 }, { width: 100 }, { width: 100 }]
|
||||
const headersDefault = [
|
||||
{ label: 'NO. SEP' },
|
||||
{ label: 'TGL. SEP' },
|
||||
{ label: 'NO. RUJUKAN' },
|
||||
{ label: 'DIAGNOSIS AWAL' },
|
||||
{ label: 'JENIS PELAYANAN' },
|
||||
{ label: 'KELAS RAWAT' },
|
||||
]
|
||||
|
||||
export const config: Config = {
|
||||
cols: [{ width: 100 }, { width: 100 }, { width: 100 }, { width: 100 }, { width: 100 }, { width: 100 }],
|
||||
cols: [...colsDefault],
|
||||
|
||||
headers: [
|
||||
[
|
||||
{ label: 'NO. SEP' },
|
||||
{ label: 'TGL. SEP' },
|
||||
{ label: 'NO. RUJUKAN' },
|
||||
{ label: 'DIAGNOSIS AWAL' },
|
||||
{ label: 'JENIS PELAYANAN' },
|
||||
{ label: 'KELAS RAWAT' },
|
||||
],
|
||||
],
|
||||
headers: [[...headersDefault]],
|
||||
|
||||
keys: ['sepNumber', 'sepDate', 'referralNumber', 'diagnosis', 'serviceType', 'careClass'],
|
||||
keys: [...keysDefault],
|
||||
|
||||
delKeyNames: [{ key: 'code', label: 'Kode' }],
|
||||
|
||||
@@ -33,3 +37,27 @@ export const config: Config = {
|
||||
|
||||
htmls: {},
|
||||
}
|
||||
|
||||
export const configDetail: Config = {
|
||||
cols: [...colsDefault, { width: 50 }],
|
||||
|
||||
headers: [[...headersDefault, { label: 'AKSI' }]],
|
||||
|
||||
keys: [...keysDefault, 'action'],
|
||||
|
||||
delKeyNames: [{ key: 'code', label: 'Kode' }],
|
||||
|
||||
parses: {},
|
||||
|
||||
components: {
|
||||
action(rec, idx) {
|
||||
return {
|
||||
idx,
|
||||
rec: { ...(rec as object) },
|
||||
component: ActionHistory,
|
||||
}
|
||||
},
|
||||
},
|
||||
|
||||
htmls: {},
|
||||
}
|
||||
|
||||
@@ -7,9 +7,10 @@ import type { SepHistoryData } from './list-cfg.history'
|
||||
import type { PaginationMeta } from '~/components/pub/my-ui/pagination/pagination.type'
|
||||
|
||||
// Configs
|
||||
import { config } from './list-cfg.history'
|
||||
import { config, configDetail } from './list-cfg.history'
|
||||
|
||||
const props = defineProps<{
|
||||
isAction?: boolean
|
||||
data: SepHistoryData[]
|
||||
paginationMeta?: PaginationMeta
|
||||
}>()
|
||||
@@ -25,7 +26,7 @@ function handlePageChange(page: number) {
|
||||
|
||||
<template>
|
||||
<PubMyUiDataTable
|
||||
v-bind="config"
|
||||
v-bind="isAction ? configDetail : config"
|
||||
:rows="props.data"
|
||||
/>
|
||||
<PaginationView
|
||||
|
||||
@@ -16,6 +16,7 @@ import type { PaginationMeta } from '~/components/pub/my-ui/pagination/paginatio
|
||||
|
||||
const props = defineProps<{
|
||||
open: boolean
|
||||
isAction?: boolean
|
||||
histories: Array<SepHistoryData>
|
||||
paginationMeta?: PaginationMeta
|
||||
}>()
|
||||
@@ -37,7 +38,7 @@ const emit = defineEmits<{
|
||||
</DialogHeader>
|
||||
|
||||
<div class="overflow-x-auto rounded-lg border">
|
||||
<ListHistory :data="histories" :pagination-meta="paginationMeta" />
|
||||
<ListHistory :data="histories" :is-action="props.isAction || false" :pagination-meta="paginationMeta" />
|
||||
</div>
|
||||
|
||||
<DialogFooter></DialogFooter>
|
||||
|
||||
@@ -3,12 +3,14 @@
|
||||
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'
|
||||
|
||||
const props = defineProps<{
|
||||
id: number
|
||||
@@ -53,6 +55,7 @@ const {
|
||||
getValidateSepNumber,
|
||||
handleFetchDoctors,
|
||||
} = useEncounterEntry(props)
|
||||
const { recSepId, openHistory, histories, getMonitoringHistoryMappers } = useIntegrationSepEntry()
|
||||
|
||||
const debouncedSepNumber = refDebounced(sepNumber, 500)
|
||||
|
||||
@@ -102,6 +105,13 @@ async function handleEvent(menu: string, value?: any) {
|
||||
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') {
|
||||
@@ -110,6 +120,7 @@ async function handleEvent(menu: string, value?: any) {
|
||||
}
|
||||
|
||||
provide('rec_select_id', recSelectId)
|
||||
provide('rec_sep_id', recSepId)
|
||||
provide('table_data_loader', isLoading)
|
||||
|
||||
watch(debouncedSepNumber, async (newValue) => {
|
||||
@@ -179,6 +190,11 @@ onMounted(async () => {
|
||||
"
|
||||
@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
|
||||
|
||||
@@ -8,7 +8,7 @@ import AppViewHistory from '~/components/app/sep/view-history.vue'
|
||||
import AppViewLetter from '~/components/app/sep/view-letter.vue'
|
||||
|
||||
// Handler
|
||||
import useIntegrationSepEntry from '~/handlers/integration-sep-entry.handler'
|
||||
import { useIntegrationSepEntry } from '~/handlers/integration-sep-entry.handler'
|
||||
|
||||
const {
|
||||
histories,
|
||||
|
||||
@@ -54,6 +54,7 @@ export function useIntegrationSepEntry() {
|
||||
const userStore = useUserStore()
|
||||
const route = useRoute()
|
||||
|
||||
const recSepId = ref<number | null>(null)
|
||||
const openPatient = ref(false)
|
||||
const openLetter = ref(false)
|
||||
const openHistory = ref(false)
|
||||
@@ -176,17 +177,17 @@ export function useIntegrationSepEntry() {
|
||||
return mappedValues
|
||||
}
|
||||
|
||||
async function getMonitoringHistoryMappers() {
|
||||
async function getMonitoringHistoryMappers(number: string | null = null) {
|
||||
histories.value = []
|
||||
const dateFirst = new Date()
|
||||
const dateLast = new Date()
|
||||
dateLast.setMonth(dateFirst.getMonth() - 3)
|
||||
dateLast.setMonth(dateFirst.getMonth() - 2) // max 90 days
|
||||
const cardNumber =
|
||||
selectedPatientObject.value?.person?.residentIdentityNumber || selectedPatientObject.value?.number || ''
|
||||
selectedPatientObject.value?.person?.residentIdentityNumber || selectedPatientObject.value?.number || number || ''
|
||||
const result = await getMonitoringHistoryList({
|
||||
cardNumber: cardNumber,
|
||||
startDate: dateFirst.toISOString().substring(0, 10),
|
||||
endDate: dateLast.toISOString().substring(0, 10),
|
||||
startDate: dateLast.toISOString().substring(0, 10),
|
||||
endDate: dateFirst.toISOString().substring(0, 10),
|
||||
})
|
||||
if (result && result.success && result.body) {
|
||||
const historiesRaw = result.body?.response?.histori || []
|
||||
@@ -636,6 +637,7 @@ export function useIntegrationSepEntry() {
|
||||
}
|
||||
|
||||
return {
|
||||
recSepId,
|
||||
openPatient,
|
||||
openLetter,
|
||||
openHistory,
|
||||
@@ -687,5 +689,3 @@ export function useIntegrationSepEntry() {
|
||||
handleInit,
|
||||
}
|
||||
}
|
||||
|
||||
export default useIntegrationSepEntry
|
||||
|
||||
Reference in New Issue
Block a user