feat: implement encounter entry form for patient, doctor, payment, and SEP management

This commit is contained in:
riefive
2025-12-04 11:59:37 +07:00
parent d2ceda37bf
commit 5da439720f
3 changed files with 96 additions and 22 deletions
+47 -15
View File
@@ -23,6 +23,7 @@ import { paymentMethodCodes } from '~/const/key-val/common'
// App things // App things
import { genEncounter, type Encounter } from '~/models/encounter' import { genEncounter, type Encounter } from '~/models/encounter'
import { se } from 'date-fns/locale'
// Props // Props
const props = defineProps<{ const props = defineProps<{
@@ -48,7 +49,7 @@ const model = defineModel<Encounter>()
model.value = genEncounter() model.value = genEncounter()
// Common preparation // Common preparation
const defaultCBItems = [{ label: 'Pilih', value: '' }]; const defaultCBItems = [{ label: 'Pilih', value: '' }]
const paymentMethodItems = CB.recStrToItem(paymentMethodCodes) const paymentMethodItems = CB.recStrToItem(paymentMethodCodes)
// Emit preparation // Emit preparation
@@ -95,7 +96,10 @@ const isInsurancePayment = computed(() => ['insurance', 'jkn'].includes(paymentM
const isDateLoading = ref(false) const isDateLoading = ref(false)
const debouncedSepNumber = refDebounced(sepNumber, 500) const debouncedSepNumber = refDebounced(sepNumber, 500)
const debouncedCardNumber = refDebounced(cardNumber, 500) const debouncedCardNumber = refDebounced(cardNumber, 500)
const sepFileReview = ref<any>(null)
const sippFileReview = ref<any>(null)
const unitFullName = ref('') // Unit, specialist, subspecialist const unitFullName = ref('') // Unit, specialist, subspecialist
const formRef = ref<HTMLFormElement | null>(null) // Expose submit method for parent component
if (mode === 'add') { if (mode === 'add') {
// Set default sepDate to current date in YYYY-MM-DD format // Set default sepDate to current date in YYYY-MM-DD format
@@ -106,11 +110,10 @@ if (mode === 'add') {
registerDate.value = `${year}-${month}-${day}` registerDate.value = `${year}-${month}-${day}`
} }
watch(() => props.selectedDoctor, (doctor) => { watch(
unitFullName.value = doctor.subspecialist?.name ?? () => props.selectedDoctor,
doctor.specialist?.name ?? (doctor) => {
doctor.unit?.name ?? unitFullName.value = doctor.subspecialist?.name ?? doctor.specialist?.name ?? doctor.unit?.name ?? 'tidak diketahui'
'tidak diketahui'
model.value!.unit_code = doctor.unit_code || '' model.value!.unit_code = doctor.unit_code || ''
model.value!.specialist_code = doctor.specialist_code || '' model.value!.specialist_code = doctor.specialist_code || ''
model.value!.subspecialist_code = doctor.subspecialist_code || '' model.value!.subspecialist_code = doctor.subspecialist_code || ''
@@ -126,12 +129,13 @@ watch(
nationalIdentity.value = objects?.nationalIdentity || '' nationalIdentity.value = objects?.nationalIdentity || ''
medicalRecordNumber.value = objects?.medicalRecordNumber || '' medicalRecordNumber.value = objects?.medicalRecordNumber || ''
doctorCode.value = objects?.doctorCode || '' doctorCode.value = objects?.doctorCode || ''
// subSpecialistCode.value = objects?.subSpecialistCode || ''
paymentMethodCode.value = objects?.paymentMethodCode || '' paymentMethodCode.value = objects?.paymentMethodCode || ''
patientCategory.value = objects?.patientCategory || '' patientCategory.value = objects?.patientCategory || ''
cardNumber.value = objects?.cardNumber || '' cardNumber.value = objects?.cardNumber || ''
sepType.value = objects?.sepType || '' sepType.value = objects?.sepType || ''
sepNumber.value = objects?.sepNumber || '' sepNumber.value = objects?.sepNumber || ''
sepFileReview.value = objects?.sepFileReview || ''
sippFileReview.value = objects?.sippFileReview || ''
isDateLoading.value = true isDateLoading.value = true
setTimeout(() => { setTimeout(() => {
registerDate.value = objects?.registerDate || '' registerDate.value = objects?.registerDate || ''
@@ -186,7 +190,7 @@ function onAddSep() {
paymentMethodCode: paymentMethodCode.value, paymentMethodCode: paymentMethodCode.value,
sepFile: sepFile.value, sepFile: sepFile.value,
sippFile: sippFile.value, sippFile: sippFile.value,
sepType: sepType.value sepType: sepType.value,
} }
emit('event', 'add-sep', formValues) emit('event', 'add-sep', formValues)
} }
@@ -197,12 +201,21 @@ function onSearchSep() {
// Submit handler // Submit handler
const onSubmit = handleSubmit((values) => { const onSubmit = handleSubmit((values) => {
console.log('✅ Validated form values:', JSON.stringify(values, null, 2)) let payload: any = values
emit('event', 'save', values) if (props.mode === 'edit') {
payload = {
...payload,
sepFileReview: sepFileReview.value,
sippFileReview: sippFileReview.value,
}
return
}
emit('event', 'save', payload)
}) })
// Expose submit method for parent component function openFile(path: string) {
const formRef = ref<HTMLFormElement | null>(null) window.open(path, '_blank')
}
function submitForm() { function submitForm() {
// Trigger form submit using native form submit // Trigger form submit using native form submit
@@ -347,7 +360,10 @@ defineExpose({
<span class="text-red-500">*</span> <span class="text-red-500">*</span>
</DE.Label> </DE.Label>
<DE.Field :errMessage="errors.unit_code"> <DE.Field :errMessage="errors.unit_code">
<Input :value="unitFullName" :disabled="true"/> <Input
:value="unitFullName"
:disabled="true"
/>
</DE.Field> </DE.Field>
</DE.Cell> </DE.Cell>
@@ -415,7 +431,7 @@ defineExpose({
placeholder="Pilih Kelompok Peserta" placeholder="Pilih Kelompok Peserta"
/> />
</DE.Field> </DE.Field>
<span class="text-sm text-gray-500"> <span class="text-sm text-gray-500">
{{ noteReference }} {{ noteReference }}
</span> </span>
</DE.Cell> </DE.Cell>
@@ -434,7 +450,7 @@ defineExpose({
placeholder="Masukkan nomor kartu BPJS" placeholder="Masukkan nomor kartu BPJS"
/> />
</DE.Field> </DE.Field>
<div <div
v-if="isMemberValid" v-if="isMemberValid"
class="mt-1 flex items-center gap-2" class="mt-1 flex items-center gap-2"
> >
@@ -559,6 +575,14 @@ defineExpose({
<span class="mt-1 text-sm text-gray-500"> <span class="mt-1 text-sm text-gray-500">
{{ noteFile }} {{ noteFile }}
</span> </span>
<a
v-if="sepFileReview"
class="text-bluered-500 mt-1 text-sm"
href="#"
@click="openFile(sepFileReview.filePath)"
>
{{ sepFileReview?.fileName }}
</a>
</DE.Cell> </DE.Cell>
<DE.Cell> <DE.Cell>
@@ -575,6 +599,14 @@ defineExpose({
<span class="mt-1 text-sm text-gray-500"> <span class="mt-1 text-sm text-gray-500">
{{ noteFile }} {{ noteFile }}
</span> </span>
<a
v-if="sippFileReview"
class="text-bluered-500 mt-1 text-sm"
href="#"
@click="openFile(sippFileReview.filePath)"
>
{{ sippFileReview?.fileName }}
</a>
</DE.Cell> </DE.Cell>
</DE.Block> </DE.Block>
</template> </template>
+34 -6
View File
@@ -13,6 +13,9 @@ import { genDoctor, type Doctor } from '~/models/doctor'
// Stores // Stores
import { useUserStore } from '~/stores/user' import { useUserStore } from '~/stores/user'
// Handlers
import { uploadAttachmentCustom } from '~/handlers/supporting-document.handler'
// Services // Services
import { import {
getList as getSpecialistList, getList as getSpecialistList,
@@ -26,7 +29,6 @@ import {
} from '~/services/encounter.service' } from '~/services/encounter.service'
import { getList as getMemberList } from '~/services/vclaim-member.service' import { getList as getMemberList } from '~/services/vclaim-member.service'
import { getList as getSepList } from '~/services/vclaim-sep.service' import { getList as getSepList } from '~/services/vclaim-sep.service'
import { uploadAttachment } from '~/services/supporting-document.service'
// Handlers // Handlers
import { import {
@@ -468,6 +470,19 @@ export function useEncounterEntry(props: {
if (formData.subSpecialistId) { if (formData.subSpecialistId) {
await handleFetchDoctors(formData.subSpecialistId) await handleFetchDoctors(formData.subSpecialistId)
} }
if (encounter.encounterDocuments && Array.isArray(encounter.encounterDocuments)) {
let sepFileReview = {}
let sippFileReview = {}
for (const doc of encounter.encounterDocuments) {
if (doc.type === 'vclaim-sep') {
sepFileReview = { id: doc.id, fileName: doc.fileName, filePath: doc.filePath, type: doc.type_code }
} else if (doc.type === 'vclaim-sipp') {
sippFileReview = { id: doc.id, fileName: doc.fileName, filePath: doc.filePath, type: doc.type_code }
}
}
formData.sepFileReview = sepFileReview
formData.sippFileReview = sippFileReview
}
formObjects.value = { ...formData } formObjects.value = { ...formData }
} }
@@ -519,7 +534,7 @@ export function useEncounterEntry(props: {
const payload: any = { const payload: any = {
patient_id: patientId, patient_id: patientId,
appointment_doctor_code: formValues.doctorCode || null, appointment_doctor_code: formValues.doctor_code || null,
class_code: props.classCode || '', class_code: props.classCode || '',
subClass_code: props.subClassCode || '', subClass_code: props.subClassCode || '',
infra_id: formValues.infra_id ?? null, infra_id: formValues.infra_id ?? null,
@@ -578,13 +593,26 @@ export function useEncounterEntry(props: {
} }
if (result.success) { if (result.success) {
// const encounterId = isEditMode.value ? props.id : result.body?.data?.id const encounterId = isEditMode.value ? props.id : result.body?.data?.id
if (patientId) {
if (encounterId) {
if (sepFile.value) { if (sepFile.value) {
await uploadAttachment(sepFile.value, patientId, 'vclaim-sep') await uploadAttachmentCustom({
id: isEditMode.value && formValues.sepFileReview ? formValues.sepFileReview.id : null,
file: sepFile.value,
refId: encounterId,
entityTypeCode: 'encounter',
type: 'vclaim-sep',
})
} }
if (sippFile.value) { if (sippFile.value) {
await uploadAttachment(sippFile.value, patientId, 'vclaim-sipp') await uploadAttachmentCustom({
id: isEditMode.value && formValues.sippFileReview ? formValues.sippFileReview.id : null,
file: sippFile.value,
refId: encounterId,
entityTypeCode: 'encounter',
type: 'vclaim-sipp',
})
} }
} }
@@ -22,3 +22,17 @@ export const {
update, update,
remove, remove,
}) })
export async function uploadAttachmentCustom(payload: any) {
const { user } = useUserStore()
const formData = new FormData()
formData.append('content', payload.file)
formData.append('entityType_code', payload.entityTypeCode)
formData.append('type_code', payload.type)
formData.append('ref_id', payload.refId)
formData.append('upload_employee_id', user.employee_id)
const response = payload.id ? await update(payload.id, formData) : await create(formData)
return response?.body?.data
}