feat: implement encounter entry form for patient, doctor, payment, and SEP management
This commit is contained in:
@@ -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>
|
||||||
|
|||||||
@@ -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 }
|
||||||
}
|
}
|
||||||
@@ -501,7 +516,7 @@ export function useEncounterEntry(props: {
|
|||||||
const visitDateValue = formValues.visitDate || formValues.registeredAt || formValues.registerDate || ''
|
const visitDateValue = formValues.visitDate || formValues.registeredAt || formValues.registerDate || ''
|
||||||
const memberNumber = formValues.member_number ?? formValues.cardNumber ?? formValues.memberNumber ?? null
|
const memberNumber = formValues.member_number ?? formValues.cardNumber ?? formValues.memberNumber ?? null
|
||||||
const refNumber = formValues.ref_number ?? formValues.sepNumber ?? formValues.refNumber ?? null
|
const refNumber = formValues.ref_number ?? formValues.sepNumber ?? formValues.refNumber ?? null
|
||||||
sepFile.value = formValues.sepFile || null
|
sepFile.value = formValues.sepFile || null
|
||||||
sippFile.value = formValues.sippFile || null
|
sippFile.value = formValues.sippFile || null
|
||||||
|
|
||||||
let paymentMethodCode = formValues.paymentMethod_code ?? null
|
let paymentMethodCode = formValues.paymentMethod_code ?? null
|
||||||
@@ -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
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user