feat(encounter): add SEP validation and handling in entry form
This commit is contained in:
No files matched your search
@@ -24,6 +24,8 @@ import { useForm } from 'vee-validate'
|
|||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
isLoading?: boolean
|
isLoading?: boolean
|
||||||
isReadonly?: boolean
|
isReadonly?: boolean
|
||||||
|
isSepValid?: boolean
|
||||||
|
isCheckingSep?: boolean
|
||||||
doctor?: any[]
|
doctor?: any[]
|
||||||
subSpecialist?: any[]
|
subSpecialist?: any[]
|
||||||
specialists?: TreeItem[]
|
specialists?: TreeItem[]
|
||||||
@@ -61,6 +63,10 @@ const patientId = ref('')
|
|||||||
const isLoading = props.isLoading !== undefined ? props.isLoading : false
|
const isLoading = props.isLoading !== undefined ? props.isLoading : false
|
||||||
const isReadonly = props.isReadonly !== undefined ? props.isReadonly : false
|
const isReadonly = props.isReadonly !== undefined ? props.isReadonly : false
|
||||||
|
|
||||||
|
// SEP validation state from props
|
||||||
|
const isSepValid = computed(() => props.isSepValid || false)
|
||||||
|
const isCheckingSep = computed(() => props.isCheckingSep || false)
|
||||||
|
|
||||||
const doctorOpts = computed(() => {
|
const doctorOpts = computed(() => {
|
||||||
// Add default option
|
// Add default option
|
||||||
const defaultOption = [{ label: 'Pilih', value: '' }]
|
const defaultOption = [{ label: 'Pilih', value: '' }]
|
||||||
@@ -86,6 +92,11 @@ watch(subSpecialistId, async (newValue) => {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// Watch SEP number changes to notify parent
|
||||||
|
watch(sepNumber, (newValue) => {
|
||||||
|
emit('event', 'sep-number-changed', newValue)
|
||||||
|
})
|
||||||
|
|
||||||
// Sync props to form fields
|
// Sync props to form fields
|
||||||
watch(
|
watch(
|
||||||
() => props.objects,
|
() => props.objects,
|
||||||
@@ -403,13 +414,33 @@ defineExpose({
|
|||||||
:disabled="isLoading || isReadonly"
|
:disabled="isLoading || isReadonly"
|
||||||
/>
|
/>
|
||||||
<Button
|
<Button
|
||||||
|
v-if="!isSepValid"
|
||||||
variant="outline"
|
variant="outline"
|
||||||
type="button"
|
type="button"
|
||||||
class="bg-primary"
|
class="bg-primary"
|
||||||
size="sm"
|
size="sm"
|
||||||
|
:disabled="isCheckingSep || isLoading || isReadonly"
|
||||||
@click="onAddSep"
|
@click="onAddSep"
|
||||||
>
|
>
|
||||||
+
|
<Icon
|
||||||
|
v-if="isCheckingSep"
|
||||||
|
name="i-lucide-loader-2"
|
||||||
|
class="h-4 w-4 animate-spin"
|
||||||
|
/>
|
||||||
|
<span v-else>+</span>
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
v-else
|
||||||
|
variant="outline"
|
||||||
|
type="button"
|
||||||
|
class="bg-green-500 text-white hover:bg-green-600"
|
||||||
|
size="sm"
|
||||||
|
disabled
|
||||||
|
>
|
||||||
|
<Icon
|
||||||
|
name="i-lucide-check"
|
||||||
|
class="h-4 w-4"
|
||||||
|
/>
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
</Field>
|
</Field>
|
||||||
|
|||||||
@@ -19,6 +19,10 @@ import {
|
|||||||
} from '~/services/specialist.service'
|
} from '~/services/specialist.service'
|
||||||
import { getValueLabelList as getDoctorValueLabelList } from '~/services/doctor.service'
|
import { getValueLabelList as getDoctorValueLabelList } from '~/services/doctor.service'
|
||||||
import { create as createEncounter, getDetail as getEncounterDetail, update as updateEncounter } from '~/services/encounter.service'
|
import { create as createEncounter, getDetail as getEncounterDetail, update as updateEncounter } from '~/services/encounter.service'
|
||||||
|
import { getList as getSepList } from '~/services/vclaim-sep.service'
|
||||||
|
|
||||||
|
// Helpers
|
||||||
|
import { refDebounced } from '@vueuse/core'
|
||||||
|
|
||||||
// Handlers
|
// Handlers
|
||||||
import {
|
import {
|
||||||
@@ -60,6 +64,12 @@ const formRef = ref<InstanceType<typeof AppEncounterEntryForm> | null>(null)
|
|||||||
const encounterData = ref<any>(null)
|
const encounterData = ref<any>(null)
|
||||||
const formObjects = ref<any>({})
|
const formObjects = ref<any>({})
|
||||||
|
|
||||||
|
// SEP validation state
|
||||||
|
const isSepValid = ref(false)
|
||||||
|
const isCheckingSep = ref(false)
|
||||||
|
const sepNumber = ref('')
|
||||||
|
const debouncedSepNumber = refDebounced(sepNumber, 500)
|
||||||
|
|
||||||
// Computed for edit mode
|
// Computed for edit mode
|
||||||
const isEditMode = computed(() => props.id > 0)
|
const isEditMode = computed(() => props.id > 0)
|
||||||
|
|
||||||
@@ -236,6 +246,10 @@ async function handleEvent(menu: string, value?: any) {
|
|||||||
} else if (menu === 'add') {
|
} else if (menu === 'add') {
|
||||||
navigateTo('/client/patient/add')
|
navigateTo('/client/patient/add')
|
||||||
} else if (menu === 'add-sep') {
|
} else if (menu === 'add-sep') {
|
||||||
|
// If SEP is already valid, don't navigate
|
||||||
|
if (isSepValid.value) {
|
||||||
|
return
|
||||||
|
}
|
||||||
recSelectId.value = null
|
recSelectId.value = null
|
||||||
toNavigateSep({
|
toNavigateSep({
|
||||||
isService: 'false',
|
isService: 'false',
|
||||||
@@ -243,6 +257,11 @@ async function handleEvent(menu: string, value?: any) {
|
|||||||
resource: `${props.classCode}-${props.subClassCode}`,
|
resource: `${props.classCode}-${props.subClassCode}`,
|
||||||
...value,
|
...value,
|
||||||
})
|
})
|
||||||
|
} else if (menu === 'sep-number-changed') {
|
||||||
|
// Update sepNumber when it changes in form (only if different to prevent loop)
|
||||||
|
if (sepNumber.value !== value) {
|
||||||
|
sepNumber.value = value || ''
|
||||||
|
}
|
||||||
} else if (menu === 'save') {
|
} else if (menu === 'save') {
|
||||||
await handleSaveEncounter(value)
|
await handleSaveEncounter(value)
|
||||||
} else if (menu === 'cancel') {
|
} else if (menu === 'cancel') {
|
||||||
@@ -250,6 +269,63 @@ async function handleEvent(menu: string, value?: any) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Validate SEP number
|
||||||
|
*/
|
||||||
|
async function validateSepNumber(sepNumberValue: string) {
|
||||||
|
// Reset validation if SEP number is empty
|
||||||
|
if (!sepNumberValue || sepNumberValue.trim() === '') {
|
||||||
|
isSepValid.value = false
|
||||||
|
isCheckingSep.value = false
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Only check if payment type is JKN
|
||||||
|
// We need to check from formObjects
|
||||||
|
const paymentType = formObjects.value?.paymentType
|
||||||
|
if (paymentType !== 'jkn') {
|
||||||
|
isSepValid.value = false
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
isCheckingSep.value = true
|
||||||
|
const result = await getSepList({ number: sepNumberValue.trim() })
|
||||||
|
|
||||||
|
// Check if SEP is found
|
||||||
|
// If response is not null, SEP is found
|
||||||
|
// If response is null with metaData code "201", SEP is not found
|
||||||
|
if (result.success && result.body?.response !== null) {
|
||||||
|
isSepValid.value = true
|
||||||
|
} else {
|
||||||
|
// SEP not found (response null with metaData code "201")
|
||||||
|
isSepValid.value = false
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error checking SEP:', error)
|
||||||
|
isSepValid.value = false
|
||||||
|
} finally {
|
||||||
|
isCheckingSep.value = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Watch debounced SEP number to validate
|
||||||
|
watch(debouncedSepNumber, async (newValue) => {
|
||||||
|
await validateSepNumber(newValue)
|
||||||
|
})
|
||||||
|
|
||||||
|
// Watch payment type to reset SEP validation
|
||||||
|
watch(
|
||||||
|
() => formObjects.value?.paymentType,
|
||||||
|
(newValue) => {
|
||||||
|
isSepValid.value = false
|
||||||
|
// If payment type is not JKN, clear SEP number
|
||||||
|
if (newValue !== 'jkn') {
|
||||||
|
sepNumber.value = ''
|
||||||
|
}
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
async function handleFetchSpecialists() {
|
async function handleFetchSpecialists() {
|
||||||
try {
|
try {
|
||||||
const specialistsResult = await getSpecialistList({ 'page-size': 100, includes: 'subspecialists' })
|
const specialistsResult = await getSpecialistList({ 'page-size': 100, includes: 'subspecialists' })
|
||||||
@@ -583,6 +659,11 @@ async function mapEncounterToForm(encounter: any) {
|
|||||||
// Set form objects for the form component
|
// Set form objects for the form component
|
||||||
formObjects.value = formData
|
formObjects.value = formData
|
||||||
|
|
||||||
|
// Update sepNumber for validation
|
||||||
|
if (formData.sepNumber) {
|
||||||
|
sepNumber.value = formData.sepNumber
|
||||||
|
}
|
||||||
|
|
||||||
// Fetch doctors based on specialist/subspecialist selection
|
// Fetch doctors based on specialist/subspecialist selection
|
||||||
if (formData.subSpecialistId) {
|
if (formData.subSpecialistId) {
|
||||||
await handleFetchDoctors(formData.subSpecialistId)
|
await handleFetchDoctors(formData.subSpecialistId)
|
||||||
@@ -613,6 +694,9 @@ onMounted(async () => {
|
|||||||
|
|
||||||
<AppEncounterEntryForm
|
<AppEncounterEntryForm
|
||||||
ref="formRef"
|
ref="formRef"
|
||||||
|
:is-loading="isLoadingDetail"
|
||||||
|
:is-sep-valid="isSepValid"
|
||||||
|
:is-checking-sep="isCheckingSep"
|
||||||
:payments="paymentsList"
|
:payments="paymentsList"
|
||||||
:seps="sepsList"
|
:seps="sepsList"
|
||||||
:participant-groups="participantGroupsList"
|
:participant-groups="participantGroupsList"
|
||||||
@@ -620,7 +704,6 @@ onMounted(async () => {
|
|||||||
:doctor="doctorsList"
|
:doctor="doctorsList"
|
||||||
:patient="selectedPatientObject"
|
:patient="selectedPatientObject"
|
||||||
:objects="formObjects"
|
:objects="formObjects"
|
||||||
:is-loading="isLoadingDetail"
|
|
||||||
@event="handleEvent"
|
@event="handleEvent"
|
||||||
@fetch="handleFetch"
|
@fetch="handleFetch"
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -11,6 +11,15 @@ export function create(data: any) {
|
|||||||
return base.create(path, data, name)
|
return base.create(path, data, name)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function getList(params: any = null) {
|
||||||
|
let url = path
|
||||||
|
if (params?.number) {
|
||||||
|
url += `/${params.number}`
|
||||||
|
delete params.number
|
||||||
|
}
|
||||||
|
return base.getList(url, params, name)
|
||||||
|
}
|
||||||
|
|
||||||
export function makeSepData(
|
export function makeSepData(
|
||||||
data: IntegrationBpjsFormData & {
|
data: IntegrationBpjsFormData & {
|
||||||
referralFrom?: string
|
referralFrom?: string
|
||||||
@@ -20,7 +29,7 @@ export function makeSepData(
|
|||||||
},
|
},
|
||||||
) {
|
) {
|
||||||
const content = {
|
const content = {
|
||||||
noKartu: data.bpjsNumber || '',
|
noKartu: data.cardNumber || '',
|
||||||
tglSep: data.sepDate,
|
tglSep: data.sepDate,
|
||||||
ppkPelayanan: data.fromClinic || '',
|
ppkPelayanan: data.fromClinic || '',
|
||||||
jnsPelayanan: data.admissionType ? String(data.admissionType) : '1',
|
jnsPelayanan: data.admissionType ? String(data.admissionType) : '1',
|
||||||
|
|||||||
Reference in New Issue
Block a user