feat: Implement patient encounter management with entry form, SEP integration, and list views.
This commit is contained in:
@@ -187,6 +187,7 @@ function onAddSep() {
|
||||
registerDate: registerDate.value,
|
||||
cardNumber: cardNumber.value,
|
||||
paymentMethodCode: paymentMethodCode.value,
|
||||
unitCode: props.selectedDoctor?.unit?.code || '',
|
||||
sepFile: sepFile.value,
|
||||
sippFile: sippFile.value,
|
||||
sepType: sepType.value,
|
||||
|
||||
@@ -1,25 +1,18 @@
|
||||
import type { Config, RecComponent } from '~/components/pub/my-ui/data-table'
|
||||
import { defineAsyncComponent } from 'vue'
|
||||
import type { Encounter } from '~/models/encounter'
|
||||
import { educationCodes, genderCodes } from '~/lib/constants'
|
||||
import { formatAddress } from '~/models/person-address'
|
||||
import { educationCodes, encounterClassCodes, genderCodes } from '~/lib/constants'
|
||||
import { getAge } from '~/lib/date'
|
||||
|
||||
type SmallDetailDto = Encounter
|
||||
|
||||
const action = defineAsyncComponent(() => import('./dropdown-action.vue'))
|
||||
const statusBadge = defineAsyncComponent(() => import('./status-badge.vue'))
|
||||
const vclaimSepInfo = defineAsyncComponent(() => import('./vclaim-sep-info.vue'))
|
||||
|
||||
export const config: Config = {
|
||||
cols: [
|
||||
{},
|
||||
{},
|
||||
{},
|
||||
{ width: 160 },
|
||||
{},
|
||||
{ width: 70 },
|
||||
{ },
|
||||
{ width: 50 },
|
||||
],
|
||||
export const defaultConfig: Config = {
|
||||
cols: [{}, {}, {}, { width: 160 }, {}, { width: 70 }, {}, { width: 50 }],
|
||||
|
||||
headers: [
|
||||
[
|
||||
@@ -94,11 +87,140 @@ export const config: Config = {
|
||||
birth_date: (rec: unknown): unknown => {
|
||||
const recX = rec as Encounter
|
||||
if (recX.patient?.person?.birthDate) {
|
||||
return '' +
|
||||
'<div>' + (recX.patient.person.birthDate as string).substring(0, 10) + ' / </div>' +
|
||||
return (
|
||||
'' +
|
||||
'<div>' +
|
||||
(recX.patient.person.birthDate as string).substring(0, 10) +
|
||||
' / </div>' +
|
||||
getAge(recX.patient.person.birthDate as string).extFormat
|
||||
)
|
||||
}
|
||||
return '-'
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
export const ambulatoryConfig: Config = {
|
||||
cols: [{}, {}, {}, { width: 160 }, {}, { width: 70 }, {}, {}, {}, {}, {}, {}, { width: 50 }],
|
||||
|
||||
headers: [
|
||||
[
|
||||
{ label: 'TANGGAL' },
|
||||
{ label: 'NO. RM' },
|
||||
{ label: 'NO. BILL' },
|
||||
{ label: 'NAMA PASIEN' },
|
||||
{ label: 'L/P' },
|
||||
{ label: 'ALAMAT' },
|
||||
{ label: 'KLINIK' },
|
||||
{ label: 'CARA BAYAR' },
|
||||
{ label: 'RUJUKAN' },
|
||||
{ label: 'KET. RUJUKAN' },
|
||||
{ label: 'ASAL' },
|
||||
{ label: 'SEP' },
|
||||
{ label: 'STATUS', classVal: '!text-center' },
|
||||
{ label: '' },
|
||||
],
|
||||
],
|
||||
|
||||
keys: [
|
||||
'registeredAt',
|
||||
'patientNumber',
|
||||
'trxNumber',
|
||||
'patient.person.name',
|
||||
'gender',
|
||||
'address',
|
||||
'clinic',
|
||||
'paymentMethod_code',
|
||||
'referral',
|
||||
'note',
|
||||
'class_code',
|
||||
'sep',
|
||||
'status',
|
||||
'action',
|
||||
],
|
||||
|
||||
delKeyNames: [
|
||||
{ key: 'code', label: 'Kode' },
|
||||
{ key: 'name', label: 'Nama' },
|
||||
],
|
||||
|
||||
parses: {
|
||||
registeredAt: (rec: unknown): unknown => {
|
||||
const recX = rec as Encounter
|
||||
return recX.registeredAt ? (recX.registeredAt as string).substring(0, 10) : '-'
|
||||
},
|
||||
patientNumber: (rec: unknown): unknown => {
|
||||
const recX = rec as any
|
||||
return recX.patient?.number || '-'
|
||||
},
|
||||
trxNumber: (rec: unknown): unknown => {
|
||||
const recX = rec as any
|
||||
return recX.trx_number || '-'
|
||||
},
|
||||
gender: (rec: unknown): unknown => {
|
||||
const recX = rec as Encounter
|
||||
if (recX.patient?.person?.gender_code) {
|
||||
return genderCodes[recX.patient.person.gender_code]
|
||||
}
|
||||
return '-'
|
||||
},
|
||||
address: (rec: unknown): unknown => {
|
||||
const recX = rec as Encounter
|
||||
const addresses = recX.patient.person.addresses
|
||||
const resident = addresses?.find((addr) => addr.locationType_code === 'domicile')
|
||||
const text = resident ? formatAddress(resident) : '-'
|
||||
return text.length > 20 ? text.substring(0, 17) + '...' : text
|
||||
},
|
||||
clinic: (rec: unknown): unknown => {
|
||||
const recX = rec as Encounter
|
||||
return recX.unit?.name || recX.refSource_name || '-'
|
||||
},
|
||||
paymentMethod_code: (rec: unknown): unknown => {
|
||||
const recX = rec as Encounter
|
||||
return (recX.paymentMethod_code || '-').toUpperCase()
|
||||
},
|
||||
referral: (rec: unknown): unknown => {
|
||||
const recX = rec as any
|
||||
return recX?.vclaimReference?.poliRujukan || '-'
|
||||
},
|
||||
note: (rec: unknown): unknown => {
|
||||
const recX = rec as any
|
||||
return recX?.vclaimReference?.ppkDirujuk || '-'
|
||||
},
|
||||
class_code: (rec: unknown): unknown => {
|
||||
const recX = rec as Encounter
|
||||
return recX.class_code ? encounterClassCodes[recX.class_code] : '-'
|
||||
},
|
||||
},
|
||||
|
||||
components: {
|
||||
sep(rec, idx) {
|
||||
const res: RecComponent = {
|
||||
rec: rec as object,
|
||||
idx,
|
||||
component: vclaimSepInfo,
|
||||
}
|
||||
return res
|
||||
},
|
||||
status(rec, idx) {
|
||||
const recX = rec as Encounter
|
||||
if (!recX.status_code) {
|
||||
recX.status_code = 'new'
|
||||
}
|
||||
const res: RecComponent = {
|
||||
idx,
|
||||
rec: recX,
|
||||
component: statusBadge,
|
||||
}
|
||||
return res
|
||||
},
|
||||
action(rec, idx) {
|
||||
const res: RecComponent = {
|
||||
idx,
|
||||
rec: rec as object,
|
||||
component: action,
|
||||
}
|
||||
return res
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
@@ -1,15 +1,16 @@
|
||||
<script setup lang="ts">
|
||||
import DataTable from '~/components/pub/my-ui/data-table/data-table.vue'
|
||||
import { config } from './list.cfg'
|
||||
import { defaultConfig, ambulatoryConfig } from './list.cfg'
|
||||
|
||||
const props = defineProps<{
|
||||
data: any[],
|
||||
data: any[]
|
||||
classCode: string | undefined
|
||||
}>()
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<DataTable
|
||||
v-bind="config"
|
||||
v-bind="props.classCode === 'ambulatory' ? ambulatoryConfig : defaultConfig"
|
||||
:rows="props.data"
|
||||
/>
|
||||
</template>
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
<script setup lang="ts">
|
||||
const props = defineProps<{
|
||||
rec: any
|
||||
idx: number
|
||||
}>()
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="flex flex-col gap-2">
|
||||
<Button
|
||||
variant="ghost"
|
||||
type="button"
|
||||
class="h-[40px] rounded-md border-orange-400 text-orange-400 hover:bg-green-50"
|
||||
>
|
||||
<Icon
|
||||
name="i-lucide-eye"
|
||||
class="h-5 w-5"
|
||||
/>
|
||||
Lihat SIPP
|
||||
</Button>
|
||||
<Button
|
||||
variant="ghost"
|
||||
type="button"
|
||||
class="h-[40px] rounded-md border-orange-400 text-orange-400 hover:bg-green-50"
|
||||
>
|
||||
<Icon
|
||||
name="i-lucide-eye"
|
||||
class="h-5 w-5"
|
||||
/>
|
||||
Lihat SEP
|
||||
</Button>
|
||||
</div>
|
||||
</template>
|
||||
@@ -136,8 +136,21 @@ 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'
|
||||
const includesParamsArrays = [
|
||||
'patient',
|
||||
'patient-person',
|
||||
'patient-person-addresses',
|
||||
'Appointment_Doctor',
|
||||
'Appointment_Doctor-employee',
|
||||
'Appointment_Doctor-employee-person',
|
||||
'Responsible_Doctor',
|
||||
'Responsible_Doctor-employee',
|
||||
'Responsible_Doctor-employee-person',
|
||||
'EncounterDocuments',
|
||||
'unit',
|
||||
'vclaimReference', // vclaimReference | vclaimSep
|
||||
]
|
||||
const includesParams = includesParamsArrays.join(',')
|
||||
data.value = []
|
||||
try {
|
||||
const params: any = { includes: includesParams, ...filterParams.value }
|
||||
@@ -270,7 +283,10 @@ function handleRemoveConfirmation() {
|
||||
/>
|
||||
</CH.ContentHeader>
|
||||
|
||||
<Content :data="data" />
|
||||
<Content
|
||||
:data="data"
|
||||
:class-code="classCode"
|
||||
/>
|
||||
|
||||
<!-- Filter -->
|
||||
<Dialog
|
||||
|
||||
@@ -539,7 +539,7 @@ export function useEncounterEntry(props: {
|
||||
class_code: props.classCode || '',
|
||||
subClass_code: props.subClassCode || '',
|
||||
infra_id: formValues.infra_id ?? null,
|
||||
unit_code: userStore?.user?.unit_code ?? null,
|
||||
unit_code: formValues.unitCode ?? userStore?.user?.unit_code ?? null,
|
||||
refSource_name: formValues.refSource_name ?? 'RSSA',
|
||||
refTypeCode: formValues.paymentType === 'jkn' ? 'bpjs' : '',
|
||||
vclaimReference: vclaimReference.value ?? null,
|
||||
@@ -547,7 +547,7 @@ export function useEncounterEntry(props: {
|
||||
registeredAt: formatDate(registeredAtValue),
|
||||
visitDate: formatDate(visitDateValue),
|
||||
}
|
||||
|
||||
|
||||
if (props.classCode !== 'inpatient') {
|
||||
delete payload.infra_id
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user