Merge pull request #194 from dikstub-rssa/feat/page-cleaning
Feat/page cleaning
This commit is contained in:
@@ -1,43 +1,57 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
// Components
|
// Components
|
||||||
import Block from '~/components/pub/my-ui/doc-entry/block.vue'
|
import * as DE from '~/components/pub/my-ui/doc-entry'
|
||||||
import Cell from '~/components/pub/my-ui/doc-entry/cell.vue'
|
|
||||||
import Field from '~/components/pub/my-ui/doc-entry/field.vue'
|
|
||||||
import Label from '~/components/pub/my-ui/doc-entry/label.vue'
|
|
||||||
import { Button } from '~/components/pub/ui/button'
|
import { Button } from '~/components/pub/ui/button'
|
||||||
import { Input } from '~/components/pub/ui/input'
|
import { Input } from '~/components/pub/ui/input'
|
||||||
import Select from '~/components/pub/ui/select/Select.vue'
|
import * as CB from '~/components/pub/my-ui/combobox'
|
||||||
import Combobox from '~/components/pub/my-ui/combobox/combobox.vue'
|
|
||||||
import DatepickerSingle from '~/components/pub/my-ui/datepicker/datepicker-single.vue'
|
import DatepickerSingle from '~/components/pub/my-ui/datepicker/datepicker-single.vue'
|
||||||
import TreeSelect from '~/components/pub/my-ui/select-tree/tree-select.vue'
|
|
||||||
import FileUpload from '~/components/pub/my-ui/form/file-field.vue'
|
import FileUpload from '~/components/pub/my-ui/form/file-field.vue'
|
||||||
|
|
||||||
// Types
|
// Types
|
||||||
import { IntegrationEncounterSchema, type IntegrationEncounterFormData } from '~/schemas/integration-encounter.schema'
|
import { IntegrationEncounterSchema, type IntegrationEncounterFormData } from '~/schemas/integration-encounter.schema'
|
||||||
import type { PatientEntity } from '~/models/patient'
|
import type { PatientEntity } from '~/models/patient'
|
||||||
import type { TreeItem } from '~/components/pub/my-ui/select-tree/type'
|
|
||||||
|
|
||||||
// Helpers
|
// Helpers
|
||||||
import { toTypedSchema } from '@vee-validate/zod'
|
import { toTypedSchema } from '@vee-validate/zod'
|
||||||
import { useForm } from 'vee-validate'
|
import { useForm } from 'vee-validate'
|
||||||
import { refDebounced } from '@vueuse/core'
|
import { refDebounced } from '@vueuse/core'
|
||||||
|
import type { Doctor } from '~/models/doctor'
|
||||||
|
|
||||||
|
// References
|
||||||
|
import { paymentMethodCodes } from '~/const/key-val/common'
|
||||||
|
|
||||||
|
// App things
|
||||||
|
import { genEncounter, type Encounter } from '~/models/encounter'
|
||||||
|
|
||||||
|
// Props
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
isLoading?: boolean
|
isLoading?: boolean
|
||||||
isReadonly?: boolean
|
isReadonly?: boolean
|
||||||
isSepValid?: boolean
|
isSepValid?: boolean
|
||||||
isCheckingSep?: boolean
|
isCheckingSep?: boolean
|
||||||
doctor?: any[]
|
doctorItems?: CB.Item[]
|
||||||
subSpecialist?: any[]
|
selectedDoctor: Doctor
|
||||||
specialists?: TreeItem[]
|
// subSpecialist?: any[]
|
||||||
payments: any[]
|
// specialists?: TreeItem[]
|
||||||
|
// paymentMethods: PaymentMethodCode[]
|
||||||
participantGroups?: any[]
|
participantGroups?: any[]
|
||||||
seps: any[]
|
seps: any[]
|
||||||
patient?: PatientEntity | null | undefined
|
patient?: PatientEntity | null | undefined
|
||||||
objects?: any
|
// objects?: any
|
||||||
}>()
|
}>()
|
||||||
|
|
||||||
|
// Model
|
||||||
|
const model = defineModel<Encounter>()
|
||||||
|
model.value = genEncounter()
|
||||||
|
|
||||||
|
// Common preparation
|
||||||
|
const defaultCBItems = [{ label: 'Pilih', value: '' }];
|
||||||
|
const paymentMethodItems = CB.recStrToItem(paymentMethodCodes)
|
||||||
|
|
||||||
|
// Emit preparation
|
||||||
const emit = defineEmits<{
|
const emit = defineEmits<{
|
||||||
|
(e: 'onSelectDoctor', code: string): void
|
||||||
(e: 'event', menu: string, value?: any): void
|
(e: 'event', menu: string, value?: any): void
|
||||||
(e: 'fetch', value?: any): void
|
(e: 'fetch', value?: any): void
|
||||||
}>()
|
}>()
|
||||||
@@ -48,10 +62,10 @@ const { handleSubmit, errors, defineField, meta } = useForm<IntegrationEncounter
|
|||||||
})
|
})
|
||||||
|
|
||||||
// Bind fields and extract attrs
|
// Bind fields and extract attrs
|
||||||
const [doctorId, doctorIdAttrs] = defineField('doctorId')
|
const [doctorCode, doctorCodeAttrs] = defineField('doctor_code')
|
||||||
const [subSpecialistId, subSpecialistIdAttrs] = defineField('subSpecialistId')
|
const [unitCode, unitCodeAttrs] = defineField('unit_code')
|
||||||
const [registerDate, registerDateAttrs] = defineField('registerDate')
|
const [registerDate, registerDateAttrs] = defineField('registerDate')
|
||||||
const [paymentType, paymentTypeAttrs] = defineField('paymentType')
|
const [paymentMethodCode, paymentMethodCodeAttrs] = defineField('paymentMethod_code')
|
||||||
const [patientCategory, patientCategoryAttrs] = defineField('patientCategory')
|
const [patientCategory, patientCategoryAttrs] = defineField('patientCategory')
|
||||||
const [cardNumber, cardNumberAttrs] = defineField('cardNumber')
|
const [cardNumber, cardNumberAttrs] = defineField('cardNumber')
|
||||||
const [sepType, sepTypeAttrs] = defineField('sepType')
|
const [sepType, sepTypeAttrs] = defineField('sepType')
|
||||||
@@ -68,30 +82,50 @@ const isReadonly = props.isReadonly !== undefined ? props.isReadonly : false
|
|||||||
const isSepValid = computed(() => props.isSepValid || false)
|
const isSepValid = computed(() => props.isSepValid || false)
|
||||||
const isCheckingSep = computed(() => props.isCheckingSep || false)
|
const isCheckingSep = computed(() => props.isCheckingSep || false)
|
||||||
|
|
||||||
const doctorOpts = computed(() => {
|
// Unit, specialist, subspecialist
|
||||||
// Add default option
|
const unitFullName = ref('')
|
||||||
const defaultOption = [{ label: 'Pilih', value: '' }]
|
watch(() => props.selectedDoctor, (doctor) => {
|
||||||
// Add doctors from props
|
unitFullName.value = doctor.subspecialist?.name ??
|
||||||
const doctors = props.doctor || []
|
doctor.specialist?.name ??
|
||||||
return [...defaultOption, ...doctors]
|
doctor.unit?.name ??
|
||||||
})
|
'tidak diketahui'
|
||||||
|
model.value!.unit_code = doctor.unit_code || ''
|
||||||
|
model.value!.specialist_code = doctor.specialist_code || ''
|
||||||
|
model.value!.subspecialist_code = doctor.subspecialist_code || ''
|
||||||
|
},
|
||||||
|
)
|
||||||
|
// const doctorOpts = computed(() => {
|
||||||
|
// const defaultOption = [{ label: 'Pilih', value: '' }]
|
||||||
|
// const doctors = props.doctors || []
|
||||||
|
// return [...defaultOption, ...doctors]
|
||||||
|
// })
|
||||||
|
// watch(doctorCode, (newValue) => {
|
||||||
|
// // doctor.value = props.doctors?.find(doc => doc.code === newValue)
|
||||||
|
// unitFullName.value = doctor.value?.subspecialist?.name ??
|
||||||
|
// doctor.value?.specialist?.name ??
|
||||||
|
// doctor.value?.unit?.name ??
|
||||||
|
// 'tidak diketahui'
|
||||||
|
// model.value!.responsible_doctor_code = doctor.value?.code
|
||||||
|
// // const unitName = selectedDoctor?.specialist?.name || ''
|
||||||
|
// // emit('event', 'unit-changed', unitName)
|
||||||
|
// })
|
||||||
|
|
||||||
const isJKNPayment = computed(() => paymentType.value === 'jkn')
|
const isJKNPayment = computed(() => paymentMethodCode.value === 'jkn')
|
||||||
|
|
||||||
async function onFetchChildren(parentId: string): Promise<void> {
|
// async function onFetchChildren(parentId: string): Promise<void> {
|
||||||
console.log('onFetchChildren', parentId)
|
// console.log('onFetchChildren', parentId)
|
||||||
}
|
// }
|
||||||
|
|
||||||
// Watch specialist/subspecialist selection to fetch doctors
|
// Watch specialist/subspecialist selection to fetch doctors
|
||||||
watch(subSpecialistId, async (newValue) => {
|
// watch(subSpecialistCode, async (newValue) => {
|
||||||
if (newValue) {
|
// if (newValue) {
|
||||||
console.log('SubSpecialist changed:', newValue)
|
// console.log('SubSpecialist changed:', newValue)
|
||||||
// Reset doctor selection
|
// // Reset doctor selection
|
||||||
doctorId.value = ''
|
// doctorCode.value = ''
|
||||||
// Emit fetch event to parent
|
// // Emit fetch event to parent
|
||||||
emit('fetch', { subSpecialistId: newValue })
|
// emit('fetch', { subSpecialistCode: newValue })
|
||||||
}
|
// }
|
||||||
})
|
// })
|
||||||
|
|
||||||
// Debounced SEP number watcher: emit change only after user stops typing
|
// Debounced SEP number watcher: emit change only after user stops typing
|
||||||
const debouncedSepNumber = refDebounced(sepNumber, 500)
|
const debouncedSepNumber = refDebounced(sepNumber, 500)
|
||||||
@@ -100,25 +134,25 @@ watch(debouncedSepNumber, (newValue) => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
// Sync props to form fields
|
// Sync props to form fields
|
||||||
watch(
|
// watch(
|
||||||
() => props.objects,
|
// () => props.objects,
|
||||||
(objects) => {
|
// (objects) => {
|
||||||
if (objects && Object.keys(objects).length > 0) {
|
// if (objects && Object.keys(objects).length > 0) {
|
||||||
patientName.value = objects?.patientName || ''
|
// patientName.value = objects?.patientName || ''
|
||||||
nationalIdentity.value = objects?.nationalIdentity || ''
|
// nationalIdentity.value = objects?.nationalIdentity || ''
|
||||||
medicalRecordNumber.value = objects?.medicalRecordNumber || ''
|
// medicalRecordNumber.value = objects?.medicalRecordNumber || ''
|
||||||
doctorId.value = objects?.doctorId || ''
|
// doctorCode.value = objects?.doctorCode || ''
|
||||||
subSpecialistId.value = objects?.subSpecialistId || ''
|
// subSpecialistCode.value = objects?.subSpecialistCode || ''
|
||||||
registerDate.value = objects?.registerDate || ''
|
// registerDate.value = objects?.registerDate || ''
|
||||||
paymentType.value = objects?.paymentType || ''
|
// 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 || ''
|
||||||
}
|
// }
|
||||||
},
|
// },
|
||||||
{ deep: true, immediate: true },
|
// { deep: true, immediate: true },
|
||||||
)
|
// )
|
||||||
|
|
||||||
watch(
|
watch(
|
||||||
() => props.patient,
|
() => props.patient,
|
||||||
@@ -136,11 +170,11 @@ watch(
|
|||||||
function onAddSep() {
|
function onAddSep() {
|
||||||
const formValues = {
|
const formValues = {
|
||||||
patientId: patientId.value || '',
|
patientId: patientId.value || '',
|
||||||
doctorCode: doctorId.value,
|
doctorCode: doctorCode.value,
|
||||||
subSpecialistCode: subSpecialistId.value,
|
// subSpecialistCode: subSpecialistCode.value,
|
||||||
registerDate: registerDate.value,
|
registerDate: registerDate.value,
|
||||||
cardNumber: cardNumber.value,
|
cardNumber: cardNumber.value,
|
||||||
paymentType: paymentType.value,
|
paymentMethodCode: paymentMethodCode.value,
|
||||||
sepType: sepType.value
|
sepType: sepType.value
|
||||||
}
|
}
|
||||||
emit('event', 'add-sep', formValues)
|
emit('event', 'add-sep', formValues)
|
||||||
@@ -158,10 +192,10 @@ const formRef = ref<HTMLFormElement | null>(null)
|
|||||||
function submitForm() {
|
function submitForm() {
|
||||||
console.log('🔵 submitForm called, formRef:', formRef.value)
|
console.log('🔵 submitForm called, formRef:', formRef.value)
|
||||||
console.log('🔵 Form values:', {
|
console.log('🔵 Form values:', {
|
||||||
doctorId: doctorId.value,
|
doctorCode: doctorCode.value,
|
||||||
subSpecialistId: subSpecialistId.value,
|
// subSpecialistCode: subSpecialistCode.value,
|
||||||
registerDate: registerDate.value,
|
registerDate: registerDate.value,
|
||||||
paymentType: paymentType.value,
|
paymentMethodCode: paymentMethodCode.value,
|
||||||
})
|
})
|
||||||
console.log('🔵 Form errors:', errors.value)
|
console.log('🔵 Form errors:', errors.value)
|
||||||
console.log('🔵 Form meta:', meta.value)
|
console.log('🔵 Form meta:', meta.value)
|
||||||
@@ -231,149 +265,151 @@ defineExpose({
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<Block
|
<DE.Block
|
||||||
labelSize="thin"
|
labelSize="thin"
|
||||||
class="!pt-0"
|
class="!pt-0"
|
||||||
:colCount="3"
|
:colCount="3"
|
||||||
:cellFlex="false"
|
:cellFlex="false"
|
||||||
>
|
>
|
||||||
<Cell>
|
<DE.Cell>
|
||||||
<Label height="compact">Nama Pasien</Label>
|
<DE.Label height="compact">Nama Pasien</DE.Label>
|
||||||
<Field :errMessage="errors.patientName">
|
<DE.Field :errMessage="errors.patientName">
|
||||||
<Input
|
<Input
|
||||||
id="patientName"
|
id="patientName"
|
||||||
v-model="patientName"
|
v-model="patientName"
|
||||||
v-bind="patientNameAttrs"
|
v-bind="patientNameAttrs"
|
||||||
:disabled="true"
|
:disabled="true"
|
||||||
/>
|
/>
|
||||||
</Field>
|
</DE.Field>
|
||||||
</Cell>
|
</DE.Cell>
|
||||||
|
|
||||||
<Cell>
|
<DE.Cell>
|
||||||
<Label height="compact">NIK</Label>
|
<DE.Label height="compact">NIK</DE.Label>
|
||||||
<Field :errMessage="errors.nationalIdentity">
|
<DE.Field :errMessage="errors.nationalIdentity">
|
||||||
<Input
|
<Input
|
||||||
id="nationalIdentity"
|
id="nationalIdentity"
|
||||||
v-model="nationalIdentity"
|
v-model="nationalIdentity"
|
||||||
v-bind="nationalIdentityAttrs"
|
v-bind="nationalIdentityAttrs"
|
||||||
:disabled="true"
|
:disabled="true"
|
||||||
/>
|
/>
|
||||||
</Field>
|
</DE.Field>
|
||||||
</Cell>
|
</DE.Cell>
|
||||||
|
|
||||||
<Cell>
|
<DE.Cell>
|
||||||
<Label height="compact">No. RM</Label>
|
<DE.Label height="compact">No. RM</DE.Label>
|
||||||
<Field :errMessage="errors.medicalRecordNumber">
|
<DE.Field :errMessage="errors.medicalRecordNumber">
|
||||||
<Input
|
<Input
|
||||||
id="medicalRecordNumber"
|
id="medicalRecordNumber"
|
||||||
v-model="medicalRecordNumber"
|
v-model="medicalRecordNumber"
|
||||||
v-bind="medicalRecordNumberAttrs"
|
v-bind="medicalRecordNumberAttrs"
|
||||||
:disabled="true"
|
:disabled="true"
|
||||||
/>
|
/>
|
||||||
</Field>
|
</DE.Field>
|
||||||
</Cell>
|
</DE.Cell>
|
||||||
</Block>
|
</DE.Block>
|
||||||
|
|
||||||
<hr />
|
<hr />
|
||||||
|
|
||||||
<!-- Data Kunjungan -->
|
<!-- Data Kunjungan -->
|
||||||
<h3 class="text-lg font-semibold">Data Kunjungan</h3>
|
<h3 class="text-lg font-semibold">Data Kunjungan</h3>
|
||||||
|
|
||||||
<Block
|
<DE.Block
|
||||||
labelSize="thin"
|
labelSize="thin"
|
||||||
class="!pt-0"
|
class="!pt-0"
|
||||||
:colCount="3"
|
:colCount="3"
|
||||||
:cellFlex="false"
|
:cellFlex="false"
|
||||||
>
|
>
|
||||||
<Cell>
|
<DE.Cell>
|
||||||
<Label height="compact">
|
<DE.Label height="compact">
|
||||||
Dokter
|
Dokter
|
||||||
<span class="text-red-500">*</span>
|
<span class="text-red-500">*</span>
|
||||||
</Label>
|
</DE.Label>
|
||||||
<Field :errMessage="errors.doctorId">
|
<DE.Field :errMessage="errors.doctor_code">
|
||||||
<Combobox
|
<CB.Combobox
|
||||||
id="doctorId"
|
id="doctorCode"
|
||||||
v-model="doctorId"
|
v-model="doctorCode"
|
||||||
v-bind="doctorIdAttrs"
|
v-bind="doctorCodeAttrs"
|
||||||
:items="doctorOpts"
|
:items="[...defaultCBItems, ...doctorItems]"
|
||||||
:is-disabled="isLoading || isReadonly"
|
:is-disabled="isLoading || isReadonly"
|
||||||
placeholder="Pilih Dokter"
|
placeholder="Pilih Dokter"
|
||||||
search-placeholder="Cari Dokter"
|
search-placeholder="Cari Dokter"
|
||||||
empty-message="Dokter tidak ditemukan"
|
empty-message="Dokter tidak ditemukan"
|
||||||
|
@update:model-value="(value) => emit('onSelectDoctor', value)"
|
||||||
/>
|
/>
|
||||||
</Field>
|
</DE.Field>
|
||||||
</Cell>
|
</DE.Cell>
|
||||||
|
|
||||||
<Cell>
|
<DE.Cell>
|
||||||
<Label height="compact">
|
<DE.Label height="compact">
|
||||||
Spesialis / Subspesialis
|
Spesialis / Subspesialis
|
||||||
<span class="text-red-500">*</span>
|
<span class="text-red-500">*</span>
|
||||||
</Label>
|
</DE.Label>
|
||||||
<Field :errMessage="errors.subSpecialistId">
|
<DE.Field :errMessage="errors.unit_code">
|
||||||
<TreeSelect
|
<Input :value="unitFullName"/>
|
||||||
id="subSpecialistId"
|
<!-- <TreeSelect
|
||||||
v-model="subSpecialistId"
|
id="subSpecialistCode"
|
||||||
v-bind="subSpecialistIdAttrs"
|
v-model="subSpecialistCode"
|
||||||
|
v-bind="subSpecialistCodeAttrs"
|
||||||
:data="specialists || []"
|
:data="specialists || []"
|
||||||
:on-fetch-children="onFetchChildren"
|
:on-fetch-children="onFetchChildren"
|
||||||
/>
|
/> -->
|
||||||
</Field>
|
</DE.Field>
|
||||||
</Cell>
|
</DE.Cell>
|
||||||
</Block>
|
</DE.Block>
|
||||||
|
|
||||||
<Block
|
<DE.Block
|
||||||
labelSize="thin"
|
labelSize="thin"
|
||||||
class="!pt-0"
|
class="!pt-0"
|
||||||
:colCount="3"
|
:colCount="3"
|
||||||
:cellFlex="false"
|
:cellFlex="false"
|
||||||
>
|
>
|
||||||
<Cell>
|
<DE.Cell>
|
||||||
<Label height="compact">
|
<DE.Label height="compact">
|
||||||
Tanggal Daftar
|
Tanggal Daftar
|
||||||
<span class="text-red-500">*</span>
|
<span class="text-red-500">*</span>
|
||||||
</Label>
|
</DE.Label>
|
||||||
<Field :errMessage="errors.registerDate">
|
<DE.Field :errMessage="errors.registerDate">
|
||||||
<DatepickerSingle
|
<DatepickerSingle
|
||||||
id="registerDate"
|
id="registerDate"
|
||||||
v-model="registerDate"
|
v-model="registerDate"
|
||||||
v-bind="registerDateAttrs"
|
v-bind="registerDateAttrs"
|
||||||
placeholder="Pilih tanggal"
|
placeholder="Pilih tanggal"
|
||||||
/>
|
/>
|
||||||
</Field>
|
</DE.Field>
|
||||||
</Cell>
|
</DE.Cell>
|
||||||
|
|
||||||
<Cell>
|
<DE.Cell>
|
||||||
<Label height="compact">
|
<DE.Label height="compact">
|
||||||
Jenis Pembayaran
|
Jenis Pembayaran
|
||||||
<span class="text-red-500">*</span>
|
<span class="text-red-500">*</span>
|
||||||
</Label>
|
</DE.Label>
|
||||||
<Field :errMessage="errors.paymentType">
|
<DE.Field :errMessage="errors.paymentMethod_code">
|
||||||
<Select
|
<CB.Combobox
|
||||||
id="paymentType"
|
id="paymentMethodCode"
|
||||||
v-model="paymentType"
|
v-model="paymentMethodCode"
|
||||||
v-bind="paymentTypeAttrs"
|
v-bind="paymentMethodCodeAttrs"
|
||||||
:items="payments"
|
:items="paymentMethodItems"
|
||||||
:disabled="isLoading || isReadonly"
|
:disabled="isLoading || isReadonly"
|
||||||
placeholder="Pilih Jenis Pembayaran"
|
placeholder="Pilih Jenis Pembayaran"
|
||||||
/>
|
/>
|
||||||
</Field>
|
</DE.Field>
|
||||||
</Cell>
|
</DE.Cell>
|
||||||
</Block>
|
</DE.Block>
|
||||||
|
|
||||||
<!-- BPJS Fields (conditional) -->
|
<!-- BPJS Fields (conditional) -->
|
||||||
<template v-if="isJKNPayment">
|
<template v-if="isJKNPayment">
|
||||||
<Block
|
<DE.Block
|
||||||
labelSize="thin"
|
labelSize="thin"
|
||||||
class="!pt-0"
|
class="!pt-0"
|
||||||
:colCount="3"
|
:colCount="3"
|
||||||
:cellFlex="false"
|
:cellFlex="false"
|
||||||
>
|
>
|
||||||
<Cell>
|
<DE.Cell>
|
||||||
<Label height="compact">
|
<DE.Label height="compact">
|
||||||
Kelompok Peserta
|
Kelompok Peserta
|
||||||
<span class="text-red-500">*</span>
|
<span class="text-red-500">*</span>
|
||||||
</Label>
|
</DE.Label>
|
||||||
<Field :errMessage="errors.patientCategory">
|
<DE.Field :errMessage="errors.patientCategory">
|
||||||
<Select
|
<Select
|
||||||
id="patientCategory"
|
id="patientCategory"
|
||||||
v-model="patientCategory"
|
v-model="patientCategory"
|
||||||
@@ -382,15 +418,15 @@ defineExpose({
|
|||||||
:disabled="isLoading || isReadonly"
|
:disabled="isLoading || isReadonly"
|
||||||
placeholder="Pilih Kelompok Peserta"
|
placeholder="Pilih Kelompok Peserta"
|
||||||
/>
|
/>
|
||||||
</Field>
|
</DE.Field>
|
||||||
</Cell>
|
</DE.Cell>
|
||||||
|
|
||||||
<Cell>
|
<DE.Cell>
|
||||||
<Label height="compact">
|
<DE.Label height="compact">
|
||||||
No. Kartu BPJS
|
No. Kartu BPJS
|
||||||
<span class="text-red-500">*</span>
|
<span class="text-red-500">*</span>
|
||||||
</Label>
|
</DE.Label>
|
||||||
<Field :errMessage="errors.cardNumber">
|
<DE.Field :errMessage="errors.cardNumber">
|
||||||
<Input
|
<Input
|
||||||
id="cardNumber"
|
id="cardNumber"
|
||||||
v-model="cardNumber"
|
v-model="cardNumber"
|
||||||
@@ -398,15 +434,15 @@ defineExpose({
|
|||||||
:disabled="isLoading || isReadonly"
|
:disabled="isLoading || isReadonly"
|
||||||
placeholder="Masukkan nomor kartu BPJS"
|
placeholder="Masukkan nomor kartu BPJS"
|
||||||
/>
|
/>
|
||||||
</Field>
|
</DE.Field>
|
||||||
</Cell>
|
</DE.Cell>
|
||||||
|
|
||||||
<Cell>
|
<DE.Cell>
|
||||||
<Label height="compact">
|
<DE.Label height="compact">
|
||||||
Jenis SEP
|
Jenis SEP
|
||||||
<span class="text-red-500">*</span>
|
<span class="text-red-500">*</span>
|
||||||
</Label>
|
</DE.Label>
|
||||||
<Field :errMessage="errors.sepType">
|
<DE.Field :errMessage="errors.sepType">
|
||||||
<Select
|
<Select
|
||||||
id="sepType"
|
id="sepType"
|
||||||
v-model="sepType"
|
v-model="sepType"
|
||||||
@@ -415,22 +451,22 @@ defineExpose({
|
|||||||
:disabled="isLoading || isReadonly"
|
:disabled="isLoading || isReadonly"
|
||||||
placeholder="Pilih Jenis SEP"
|
placeholder="Pilih Jenis SEP"
|
||||||
/>
|
/>
|
||||||
</Field>
|
</DE.Field>
|
||||||
</Cell>
|
</DE.Cell>
|
||||||
</Block>
|
</DE.Block>
|
||||||
|
|
||||||
<Block
|
<DE.Block
|
||||||
labelSize="thin"
|
labelSize="thin"
|
||||||
class="!pt-0"
|
class="!pt-0"
|
||||||
:colCount="3"
|
:colCount="3"
|
||||||
:cellFlex="false"
|
:cellFlex="false"
|
||||||
>
|
>
|
||||||
<Cell>
|
<DE.Cell>
|
||||||
<Label height="compact">
|
<DE.Label height="compact">
|
||||||
No. SEP
|
No. SEP
|
||||||
<span class="text-red-500">*</span>
|
<span class="text-red-500">*</span>
|
||||||
</Label>
|
</DE.Label>
|
||||||
<Field :errMessage="errors.sepNumber">
|
<DE.Field :errMessage="errors.sepNumber">
|
||||||
<div class="flex gap-2">
|
<div class="flex gap-2">
|
||||||
<Input
|
<Input
|
||||||
id="sepNumber"
|
id="sepNumber"
|
||||||
@@ -474,8 +510,8 @@ defineExpose({
|
|||||||
/>
|
/>
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
</Field>
|
</DE.Field>
|
||||||
</Cell>
|
</DE.Cell>
|
||||||
|
|
||||||
<FileUpload
|
<FileUpload
|
||||||
field-name="sepFile"
|
field-name="sepFile"
|
||||||
@@ -492,7 +528,7 @@ defineExpose({
|
|||||||
:accept="['pdf', 'jpg', 'png']"
|
:accept="['pdf', 'jpg', 'png']"
|
||||||
:max-size-mb="1"
|
:max-size-mb="1"
|
||||||
/>
|
/>
|
||||||
</Block>
|
</DE.Block>
|
||||||
</template>
|
</template>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -0,0 +1,499 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
// Components
|
||||||
|
import Block from '~/components/pub/my-ui/doc-entry/block.vue'
|
||||||
|
import Cell from '~/components/pub/my-ui/doc-entry/cell.vue'
|
||||||
|
import Field from '~/components/pub/my-ui/doc-entry/field.vue'
|
||||||
|
import Label from '~/components/pub/my-ui/doc-entry/label.vue'
|
||||||
|
import { Button } from '~/components/pub/ui/button'
|
||||||
|
import { Input } from '~/components/pub/ui/input'
|
||||||
|
import Select from '~/components/pub/ui/select/Select.vue'
|
||||||
|
import Combobox from '~/components/pub/my-ui/combobox/combobox.vue'
|
||||||
|
import DatepickerSingle from '~/components/pub/my-ui/datepicker/datepicker-single.vue'
|
||||||
|
import TreeSelect from '~/components/pub/my-ui/select-tree/tree-select.vue'
|
||||||
|
import FileUpload from '~/components/pub/my-ui/form/file-field.vue'
|
||||||
|
|
||||||
|
// Types
|
||||||
|
import { IntegrationEncounterSchema, type IntegrationEncounterFormData } from '~/schemas/integration-encounter.schema'
|
||||||
|
import type { PatientEntity } from '~/models/patient'
|
||||||
|
import type { TreeItem } from '~/components/pub/my-ui/select-tree/type'
|
||||||
|
|
||||||
|
// Helpers
|
||||||
|
import { toTypedSchema } from '@vee-validate/zod'
|
||||||
|
import { useForm } from 'vee-validate'
|
||||||
|
import { refDebounced } from '@vueuse/core'
|
||||||
|
|
||||||
|
const props = defineProps<{
|
||||||
|
isLoading?: boolean
|
||||||
|
isReadonly?: boolean
|
||||||
|
isSepValid?: boolean
|
||||||
|
isCheckingSep?: boolean
|
||||||
|
doctor?: any[]
|
||||||
|
subSpecialist?: any[]
|
||||||
|
specialists?: TreeItem[]
|
||||||
|
payments: any[]
|
||||||
|
participantGroups?: any[]
|
||||||
|
seps: any[]
|
||||||
|
patient?: PatientEntity | null | undefined
|
||||||
|
objects?: any
|
||||||
|
}>()
|
||||||
|
|
||||||
|
const emit = defineEmits<{
|
||||||
|
(e: 'event', menu: string, value?: any): void
|
||||||
|
(e: 'fetch', value?: any): void
|
||||||
|
}>()
|
||||||
|
|
||||||
|
// Validation schema
|
||||||
|
const { handleSubmit, errors, defineField, meta } = useForm<IntegrationEncounterFormData>({
|
||||||
|
validationSchema: toTypedSchema(IntegrationEncounterSchema),
|
||||||
|
})
|
||||||
|
|
||||||
|
// Bind fields and extract attrs
|
||||||
|
const [doctorId, doctorIdAttrs] = defineField('doctorId')
|
||||||
|
const [subSpecialistId, subSpecialistIdAttrs] = defineField('subSpecialistId')
|
||||||
|
const [registerDate, registerDateAttrs] = defineField('registerDate')
|
||||||
|
const [paymentType, paymentTypeAttrs] = defineField('paymentType')
|
||||||
|
const [patientCategory, patientCategoryAttrs] = defineField('patientCategory')
|
||||||
|
const [cardNumber, cardNumberAttrs] = defineField('cardNumber')
|
||||||
|
const [sepType, sepTypeAttrs] = defineField('sepType')
|
||||||
|
const [sepNumber, sepNumberAttrs] = defineField('sepNumber')
|
||||||
|
const [patientName, patientNameAttrs] = defineField('patientName')
|
||||||
|
const [nationalIdentity, nationalIdentityAttrs] = defineField('nationalIdentity')
|
||||||
|
const [medicalRecordNumber, medicalRecordNumberAttrs] = defineField('medicalRecordNumber')
|
||||||
|
const patientId = ref('')
|
||||||
|
|
||||||
|
const isLoading = props.isLoading !== undefined ? props.isLoading : 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(() => {
|
||||||
|
// Add default option
|
||||||
|
const defaultOption = [{ label: 'Pilih', value: '' }]
|
||||||
|
// Add doctors from props
|
||||||
|
const doctors = props.doctor || []
|
||||||
|
return [...defaultOption, ...doctors]
|
||||||
|
})
|
||||||
|
|
||||||
|
const isJKNPayment = computed(() => paymentType.value === 'jkn')
|
||||||
|
|
||||||
|
async function onFetchChildren(parentId: string): Promise<void> {
|
||||||
|
console.log('onFetchChildren', parentId)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Watch specialist/subspecialist selection to fetch doctors
|
||||||
|
watch(subSpecialistId, async (newValue) => {
|
||||||
|
if (newValue) {
|
||||||
|
console.log('SubSpecialist changed:', newValue)
|
||||||
|
// Reset doctor selection
|
||||||
|
doctorId.value = ''
|
||||||
|
// Emit fetch event to parent
|
||||||
|
emit('fetch', { subSpecialistId: newValue })
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
// Debounced SEP number watcher: emit change only after user stops typing
|
||||||
|
const debouncedSepNumber = refDebounced(sepNumber, 500)
|
||||||
|
watch(debouncedSepNumber, (newValue) => {
|
||||||
|
emit('event', 'sep-number-changed', newValue)
|
||||||
|
})
|
||||||
|
|
||||||
|
// Sync props to form fields
|
||||||
|
watch(
|
||||||
|
() => props.objects,
|
||||||
|
(objects) => {
|
||||||
|
if (objects && Object.keys(objects).length > 0) {
|
||||||
|
patientName.value = objects?.patientName || ''
|
||||||
|
nationalIdentity.value = objects?.nationalIdentity || ''
|
||||||
|
medicalRecordNumber.value = objects?.medicalRecordNumber || ''
|
||||||
|
doctorId.value = objects?.doctorId || ''
|
||||||
|
subSpecialistId.value = objects?.subSpecialistId || ''
|
||||||
|
registerDate.value = objects?.registerDate || ''
|
||||||
|
paymentType.value = objects?.paymentType || ''
|
||||||
|
patientCategory.value = objects?.patientCategory || ''
|
||||||
|
cardNumber.value = objects?.cardNumber || ''
|
||||||
|
sepType.value = objects?.sepType || ''
|
||||||
|
sepNumber.value = objects?.sepNumber || ''
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{ deep: true, immediate: true },
|
||||||
|
)
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => props.patient,
|
||||||
|
(patient) => {
|
||||||
|
if (patient && Object.keys(patient).length > 0) {
|
||||||
|
patientId.value = patient?.id ? String(patient.id) : ''
|
||||||
|
patientName.value = patient?.person?.name || ''
|
||||||
|
nationalIdentity.value = patient?.person?.residentIdentityNumber || ''
|
||||||
|
medicalRecordNumber.value = patient?.number || ''
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{ deep: true, immediate: true },
|
||||||
|
)
|
||||||
|
|
||||||
|
function onAddSep() {
|
||||||
|
const formValues = {
|
||||||
|
patientId: patientId.value || '',
|
||||||
|
doctorCode: doctorId.value,
|
||||||
|
subSpecialistCode: subSpecialistId.value,
|
||||||
|
registerDate: registerDate.value,
|
||||||
|
cardNumber: cardNumber.value,
|
||||||
|
paymentType: paymentType.value,
|
||||||
|
sepType: sepType.value
|
||||||
|
}
|
||||||
|
emit('event', 'add-sep', formValues)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Submit handler
|
||||||
|
const onSubmit = handleSubmit((values) => {
|
||||||
|
console.log('✅ Validated form values:', JSON.stringify(values, null, 2))
|
||||||
|
emit('event', 'save', values)
|
||||||
|
})
|
||||||
|
|
||||||
|
// Expose submit method for parent component
|
||||||
|
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 = {
|
||||||
|
preventDefault: () => {},
|
||||||
|
target: formRef.value || {},
|
||||||
|
} as SubmitEvent
|
||||||
|
|
||||||
|
// Call onSubmit directly
|
||||||
|
console.log('🔵 Calling onSubmit with mock event')
|
||||||
|
onSubmit(mockEvent)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
defineExpose({
|
||||||
|
submitForm,
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="mx-auto w-full">
|
||||||
|
<form
|
||||||
|
ref="formRef"
|
||||||
|
@submit.prevent="onSubmit"
|
||||||
|
class="grid gap-6 p-4"
|
||||||
|
>
|
||||||
|
<!-- Data Pasien -->
|
||||||
|
<div class="flex flex-col gap-2">
|
||||||
|
<h3 class="text-lg font-semibold">Data Pasien</h3>
|
||||||
|
<div class="flex items-center gap-2">
|
||||||
|
<span class="text-sm">sudah pernah terdaftar sebagai pasien?</span>
|
||||||
|
<Button
|
||||||
|
variant="outline"
|
||||||
|
type="button"
|
||||||
|
class="h-[40px] rounded-md border-orange-400 text-orange-400 hover:bg-green-50"
|
||||||
|
@click="emit('event', 'search')"
|
||||||
|
>
|
||||||
|
<Icon
|
||||||
|
name="i-lucide-search"
|
||||||
|
class="h-5 w-5"
|
||||||
|
/>
|
||||||
|
Cari Pasien
|
||||||
|
</Button>
|
||||||
|
<span class="text-sm">belum pernah terdaftar sebagai pasien?</span>
|
||||||
|
<Button
|
||||||
|
variant="outline"
|
||||||
|
type="button"
|
||||||
|
class="h-[40px] rounded-md border-orange-400 text-orange-400 hover:bg-green-50"
|
||||||
|
@click="emit('event', 'add')"
|
||||||
|
>
|
||||||
|
<Icon
|
||||||
|
name="i-lucide-plus"
|
||||||
|
class="h-5 w-5"
|
||||||
|
/>
|
||||||
|
Tambah Pasien Baru
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<Block
|
||||||
|
labelSize="thin"
|
||||||
|
class="!pt-0"
|
||||||
|
:colCount="3"
|
||||||
|
:cellFlex="false"
|
||||||
|
>
|
||||||
|
<Cell>
|
||||||
|
<Label height="compact">Nama Pasien</Label>
|
||||||
|
<Field :errMessage="errors.patientName">
|
||||||
|
<Input
|
||||||
|
id="patientName"
|
||||||
|
v-model="patientName"
|
||||||
|
v-bind="patientNameAttrs"
|
||||||
|
:disabled="true"
|
||||||
|
/>
|
||||||
|
</Field>
|
||||||
|
</Cell>
|
||||||
|
|
||||||
|
<Cell>
|
||||||
|
<Label height="compact">NIK</Label>
|
||||||
|
<Field :errMessage="errors.nationalIdentity">
|
||||||
|
<Input
|
||||||
|
id="nationalIdentity"
|
||||||
|
v-model="nationalIdentity"
|
||||||
|
v-bind="nationalIdentityAttrs"
|
||||||
|
:disabled="true"
|
||||||
|
/>
|
||||||
|
</Field>
|
||||||
|
</Cell>
|
||||||
|
|
||||||
|
<Cell>
|
||||||
|
<Label height="compact">No. RM</Label>
|
||||||
|
<Field :errMessage="errors.medicalRecordNumber">
|
||||||
|
<Input
|
||||||
|
id="medicalRecordNumber"
|
||||||
|
v-model="medicalRecordNumber"
|
||||||
|
v-bind="medicalRecordNumberAttrs"
|
||||||
|
:disabled="true"
|
||||||
|
/>
|
||||||
|
</Field>
|
||||||
|
</Cell>
|
||||||
|
</Block>
|
||||||
|
|
||||||
|
<hr />
|
||||||
|
|
||||||
|
<!-- Data Kunjungan -->
|
||||||
|
<h3 class="text-lg font-semibold">Data Kunjungan</h3>
|
||||||
|
|
||||||
|
<Block
|
||||||
|
labelSize="thin"
|
||||||
|
class="!pt-0"
|
||||||
|
:colCount="3"
|
||||||
|
:cellFlex="false"
|
||||||
|
>
|
||||||
|
<Cell>
|
||||||
|
<Label height="compact">
|
||||||
|
Dokter
|
||||||
|
<span class="text-red-500">*</span>
|
||||||
|
</Label>
|
||||||
|
<Field :errMessage="errors.doctorId">
|
||||||
|
<Combobox
|
||||||
|
id="doctorId"
|
||||||
|
v-model="doctorId"
|
||||||
|
v-bind="doctorIdAttrs"
|
||||||
|
:items="doctorOpts"
|
||||||
|
:is-disabled="isLoading || isReadonly"
|
||||||
|
placeholder="Pilih Dokter"
|
||||||
|
search-placeholder="Cari Dokter"
|
||||||
|
empty-message="Dokter tidak ditemukan"
|
||||||
|
/>
|
||||||
|
</Field>
|
||||||
|
</Cell>
|
||||||
|
|
||||||
|
<Cell>
|
||||||
|
<Label height="compact">
|
||||||
|
Spesialis / Subspesialis
|
||||||
|
<span class="text-red-500">*</span>
|
||||||
|
</Label>
|
||||||
|
<Field :errMessage="errors.subSpecialistId">
|
||||||
|
<TreeSelect
|
||||||
|
id="subSpecialistId"
|
||||||
|
v-model="subSpecialistId"
|
||||||
|
v-bind="subSpecialistIdAttrs"
|
||||||
|
:data="specialists || []"
|
||||||
|
:on-fetch-children="onFetchChildren"
|
||||||
|
/>
|
||||||
|
</Field>
|
||||||
|
</Cell>
|
||||||
|
</Block>
|
||||||
|
|
||||||
|
<Block
|
||||||
|
labelSize="thin"
|
||||||
|
class="!pt-0"
|
||||||
|
:colCount="3"
|
||||||
|
:cellFlex="false"
|
||||||
|
>
|
||||||
|
<Cell>
|
||||||
|
<Label height="compact">
|
||||||
|
Tanggal Daftar
|
||||||
|
<span class="text-red-500">*</span>
|
||||||
|
</Label>
|
||||||
|
<Field :errMessage="errors.registerDate">
|
||||||
|
<DatepickerSingle
|
||||||
|
id="registerDate"
|
||||||
|
v-model="registerDate"
|
||||||
|
v-bind="registerDateAttrs"
|
||||||
|
placeholder="Pilih tanggal"
|
||||||
|
/>
|
||||||
|
</Field>
|
||||||
|
</Cell>
|
||||||
|
|
||||||
|
<Cell>
|
||||||
|
<Label height="compact">
|
||||||
|
Jenis Pembayaran
|
||||||
|
<span class="text-red-500">*</span>
|
||||||
|
</Label>
|
||||||
|
<Field :errMessage="errors.paymentType">
|
||||||
|
<Select
|
||||||
|
id="paymentType"
|
||||||
|
v-model="paymentType"
|
||||||
|
v-bind="paymentTypeAttrs"
|
||||||
|
:items="payments"
|
||||||
|
:disabled="isLoading || isReadonly"
|
||||||
|
placeholder="Pilih Jenis Pembayaran"
|
||||||
|
/>
|
||||||
|
</Field>
|
||||||
|
</Cell>
|
||||||
|
</Block>
|
||||||
|
|
||||||
|
<!-- BPJS Fields (conditional) -->
|
||||||
|
<template v-if="isJKNPayment">
|
||||||
|
<Block
|
||||||
|
labelSize="thin"
|
||||||
|
class="!pt-0"
|
||||||
|
:colCount="3"
|
||||||
|
:cellFlex="false"
|
||||||
|
>
|
||||||
|
<Cell>
|
||||||
|
<Label height="compact">
|
||||||
|
Kelompok Peserta
|
||||||
|
<span class="text-red-500">*</span>
|
||||||
|
</Label>
|
||||||
|
<Field :errMessage="errors.patientCategory">
|
||||||
|
<Select
|
||||||
|
id="patientCategory"
|
||||||
|
v-model="patientCategory"
|
||||||
|
v-bind="patientCategoryAttrs"
|
||||||
|
:items="participantGroups || []"
|
||||||
|
:disabled="isLoading || isReadonly"
|
||||||
|
placeholder="Pilih Kelompok Peserta"
|
||||||
|
/>
|
||||||
|
</Field>
|
||||||
|
</Cell>
|
||||||
|
|
||||||
|
<Cell>
|
||||||
|
<Label height="compact">
|
||||||
|
No. Kartu BPJS
|
||||||
|
<span class="text-red-500">*</span>
|
||||||
|
</Label>
|
||||||
|
<Field :errMessage="errors.cardNumber">
|
||||||
|
<Input
|
||||||
|
id="cardNumber"
|
||||||
|
v-model="cardNumber"
|
||||||
|
v-bind="cardNumberAttrs"
|
||||||
|
:disabled="isLoading || isReadonly"
|
||||||
|
placeholder="Masukkan nomor kartu BPJS"
|
||||||
|
/>
|
||||||
|
</Field>
|
||||||
|
</Cell>
|
||||||
|
|
||||||
|
<Cell>
|
||||||
|
<Label height="compact">
|
||||||
|
Jenis SEP
|
||||||
|
<span class="text-red-500">*</span>
|
||||||
|
</Label>
|
||||||
|
<Field :errMessage="errors.sepType">
|
||||||
|
<Select
|
||||||
|
id="sepType"
|
||||||
|
v-model="sepType"
|
||||||
|
v-bind="sepTypeAttrs"
|
||||||
|
:items="seps"
|
||||||
|
:disabled="isLoading || isReadonly"
|
||||||
|
placeholder="Pilih Jenis SEP"
|
||||||
|
/>
|
||||||
|
</Field>
|
||||||
|
</Cell>
|
||||||
|
</Block>
|
||||||
|
|
||||||
|
<Block
|
||||||
|
labelSize="thin"
|
||||||
|
class="!pt-0"
|
||||||
|
:colCount="3"
|
||||||
|
:cellFlex="false"
|
||||||
|
>
|
||||||
|
<Cell>
|
||||||
|
<Label height="compact">
|
||||||
|
No. SEP
|
||||||
|
<span class="text-red-500">*</span>
|
||||||
|
</Label>
|
||||||
|
<Field :errMessage="errors.sepNumber">
|
||||||
|
<div class="flex gap-2">
|
||||||
|
<Input
|
||||||
|
id="sepNumber"
|
||||||
|
v-model="sepNumber"
|
||||||
|
v-bind="sepNumberAttrs"
|
||||||
|
placeholder="Tambah SEP terlebih dahulu"
|
||||||
|
class="flex-1"
|
||||||
|
:disabled="isLoading || isReadonly"
|
||||||
|
/>
|
||||||
|
<Button
|
||||||
|
v-if="!isSepValid"
|
||||||
|
variant="outline"
|
||||||
|
type="button"
|
||||||
|
class="bg-primary"
|
||||||
|
size="sm"
|
||||||
|
:disabled="isCheckingSep || isLoading || isReadonly"
|
||||||
|
@click="onAddSep"
|
||||||
|
>
|
||||||
|
<Icon
|
||||||
|
v-if="isCheckingSep"
|
||||||
|
name="i-lucide-loader-2"
|
||||||
|
class="h-4 w-4 animate-spin"
|
||||||
|
/>
|
||||||
|
<Icon
|
||||||
|
v-else
|
||||||
|
name="i-lucide-plus"
|
||||||
|
class="h-4 w-4"
|
||||||
|
/>
|
||||||
|
</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>
|
||||||
|
</div>
|
||||||
|
</Field>
|
||||||
|
</Cell>
|
||||||
|
|
||||||
|
<FileUpload
|
||||||
|
field-name="sepFile"
|
||||||
|
label="Dokumen SEP"
|
||||||
|
placeholder="Unggah dokumen SEP"
|
||||||
|
:accept="['pdf', 'jpg', 'png']"
|
||||||
|
:max-size-mb="1"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<FileUpload
|
||||||
|
field-name="sippFile"
|
||||||
|
label="Dokumen SIPP"
|
||||||
|
placeholder="Unggah dokumen SIPP"
|
||||||
|
:accept="['pdf', 'jpg', 'png']"
|
||||||
|
:max-size-mb="1"
|
||||||
|
/>
|
||||||
|
</Block>
|
||||||
|
</template>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
@@ -7,17 +7,37 @@ const props = defineProps<{
|
|||||||
data: Encounter
|
data: Encounter
|
||||||
}>()
|
}>()
|
||||||
|
|
||||||
let address = ref('')
|
const addressText = computed(() => {
|
||||||
if (props.data.patient.person.addresses) {
|
if (props.data.patient.person.addresses && props.data.patient.person.addresses.length > 0) {
|
||||||
address.value = props.data.patient.person.addresses.map((a) => a.address).join(', ')
|
return props.data.patient.person.addresses.map((a) => a.address).join(', ')
|
||||||
}
|
}
|
||||||
|
return '-'
|
||||||
|
})
|
||||||
|
|
||||||
let dpjp = ref('')
|
const paymentMethodText = computed(() => {
|
||||||
|
const code = props.data.paymentMethod_code
|
||||||
|
if (!code) return '-'
|
||||||
|
|
||||||
|
// Map payment method codes
|
||||||
|
if (code === 'insurance') {
|
||||||
|
return 'JKN'
|
||||||
|
} else if (code === 'jkn') {
|
||||||
|
return 'JKN'
|
||||||
|
} else if (code === 'jkmm') {
|
||||||
|
return 'JKMM'
|
||||||
|
} else if (code === 'spm') {
|
||||||
|
return 'SPM'
|
||||||
|
} else if (code === 'pks') {
|
||||||
|
return 'PKS'
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
let dpjpText = ref('')
|
||||||
if (props.data.responsible_doctor) {
|
if (props.data.responsible_doctor) {
|
||||||
const dp = props.data.responsible_doctor.employee.person
|
const dp = props.data.responsible_doctor.employee.person
|
||||||
dpjp.value = `${dp.frontTitle} ${dp.name} ${dp.endTitle}`
|
dpjpText.value = `${dp.frontTitle} ${dp.name} ${dp.endTitle}`
|
||||||
} else if (props.data.appointment_doctor) {
|
} else if (props.data.appointment_doctor) {
|
||||||
dpjp.value = props.data.appointment_doctor.employee.person.name
|
dpjpText.value = props.data.appointment_doctor.employee.person.name
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
@@ -31,7 +51,7 @@ if (props.data.responsible_doctor) {
|
|||||||
<div>
|
<div>
|
||||||
<DE.Block mode="preview">
|
<DE.Block mode="preview">
|
||||||
<DE.Cell>
|
<DE.Cell>
|
||||||
<DE.Label class="font-semibold">No. RM</DE.Label>
|
<DE.Label class="font-semibold">Tgl. Lahir</DE.Label>
|
||||||
<DE.Colon />
|
<DE.Colon />
|
||||||
<DE.Field>
|
<DE.Field>
|
||||||
{{ data.patient.person.birthDate?.substring(0, 10) }}
|
{{ data.patient.person.birthDate?.substring(0, 10) }}
|
||||||
@@ -48,7 +68,7 @@ if (props.data.responsible_doctor) {
|
|||||||
<DE.Label class="font-semibold">Alamat</DE.Label>
|
<DE.Label class="font-semibold">Alamat</DE.Label>
|
||||||
<DE.Colon />
|
<DE.Colon />
|
||||||
<DE.Field>
|
<DE.Field>
|
||||||
<div v-html="address"></div>
|
{{ addressText }}
|
||||||
</DE.Field>
|
</DE.Field>
|
||||||
</DE.Cell>
|
</DE.Cell>
|
||||||
</DE.Block>
|
</DE.Block>
|
||||||
@@ -70,7 +90,7 @@ if (props.data.responsible_doctor) {
|
|||||||
</DE.Field>
|
</DE.Field>
|
||||||
</DE.Cell>
|
</DE.Cell>
|
||||||
<DE.Cell>
|
<DE.Cell>
|
||||||
<DE.Label position="dynamic" class="font-semibold">Klinik</DE.Label>
|
<DE.Label position="dynamic" class="font-semibold">Diagnosa</DE.Label>
|
||||||
<DE.Colon />
|
<DE.Colon />
|
||||||
<DE.Field>
|
<DE.Field>
|
||||||
{{ data.unit?.name }}
|
{{ data.unit?.name }}
|
||||||
@@ -84,17 +104,21 @@ if (props.data.responsible_doctor) {
|
|||||||
<DE.Label position="dynamic" class="font-semibold">DPJP</DE.Label>
|
<DE.Label position="dynamic" class="font-semibold">DPJP</DE.Label>
|
||||||
<DE.Colon />
|
<DE.Colon />
|
||||||
<DE.Field>
|
<DE.Field>
|
||||||
{{ dpjp }}
|
{{ dpjpText }}
|
||||||
</DE.Field>
|
</DE.Field>
|
||||||
</DE.Cell>
|
</DE.Cell>
|
||||||
<DE.Cell>
|
<DE.Cell>
|
||||||
<DE.Label
|
<DE.Label position="dynamic" class="font-semibold">Pembayaran</DE.Label>
|
||||||
position="dynamic"
|
<DE.Colon />
|
||||||
class="!text-base font-semibold 2xl:!text-lg"
|
<DE.Field>
|
||||||
>
|
{{ paymentMethodText }}
|
||||||
|
</DE.Field>
|
||||||
|
</DE.Cell>
|
||||||
|
<DE.Cell>
|
||||||
|
<DE.Label position="dynamic" class="!text-base !font-semibold 2xl:!text-lg">
|
||||||
Billing
|
Billing
|
||||||
</DE.Label>
|
</DE.Label>
|
||||||
<DE.Colon class="pt-1" />
|
<DE.Colon class="pt-1"/>
|
||||||
<DE.Field class="text-base 2xl:text-lg">
|
<DE.Field class="text-base 2xl:text-lg">
|
||||||
Rp. 000.000
|
Rp. 000.000
|
||||||
<!-- {{ data }} -->
|
<!-- {{ data }} -->
|
||||||
|
|||||||
@@ -8,8 +8,11 @@ import AppViewPatient from '~/components/app/patient/view-patient.vue'
|
|||||||
import { refDebounced } from '@vueuse/core'
|
import { refDebounced } from '@vueuse/core'
|
||||||
|
|
||||||
// Handlers
|
// Handlers
|
||||||
|
import { getDetail as getDoctorDetail } from '~/services/doctor.service'
|
||||||
import { useEncounterEntry } from '~/handlers/encounter-entry.handler'
|
import { useEncounterEntry } from '~/handlers/encounter-entry.handler'
|
||||||
|
import { genDoctor, type Doctor } from '~/models/doctor'
|
||||||
|
|
||||||
|
// Props
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
id: number
|
id: number
|
||||||
classCode?: 'ambulatory' | 'emergency' | 'inpatient' | 'outpatient'
|
classCode?: 'ambulatory' | 'emergency' | 'inpatient' | 'outpatient'
|
||||||
@@ -54,7 +57,33 @@ const {
|
|||||||
} = useEncounterEntry(props)
|
} = useEncounterEntry(props)
|
||||||
|
|
||||||
const debouncedSepNumber = refDebounced(sepNumber, 500)
|
const debouncedSepNumber = refDebounced(sepNumber, 500)
|
||||||
|
const selectedDoctor = ref<Doctor>(genDoctor())
|
||||||
|
|
||||||
|
provide('rec_select_id', recSelectId)
|
||||||
|
provide('table_data_loader', isLoading)
|
||||||
|
|
||||||
|
watch(debouncedSepNumber, async (newValue) => {
|
||||||
|
await getValidateSepNumber(newValue)
|
||||||
|
})
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => formObjects.value?.paymentType,
|
||||||
|
(newValue) => {
|
||||||
|
isSepValid.value = false
|
||||||
|
if (newValue !== 'jkn') {
|
||||||
|
sepNumber.value = ''
|
||||||
|
}
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
onMounted(async () => {
|
||||||
|
await handleInit()
|
||||||
|
if (props.id > 0) {
|
||||||
|
await loadEncounterDetail()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
///// Functions
|
||||||
function handleSavePatient() {
|
function handleSavePatient() {
|
||||||
selectedPatientObject.value = null
|
selectedPatientObject.value = null
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
@@ -100,29 +129,13 @@ async function handleEvent(menu: string, value?: any) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
provide('rec_select_id', recSelectId)
|
async function getDoctorInfo(value: string) {
|
||||||
provide('table_data_loader', isLoading)
|
const resp = await getDoctorDetail(value, { includes: 'unit,specialist,subspecialist'})
|
||||||
|
if (resp.success) {
|
||||||
watch(debouncedSepNumber, async (newValue) => {
|
selectedDoctor.value = resp.body.data
|
||||||
await getValidateSepNumber(newValue)
|
// console.log(selectedDoctor.value)
|
||||||
})
|
|
||||||
|
|
||||||
watch(
|
|
||||||
() => formObjects.value?.paymentType,
|
|
||||||
(newValue) => {
|
|
||||||
isSepValid.value = false
|
|
||||||
if (newValue !== 'jkn') {
|
|
||||||
sepNumber.value = ''
|
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
)
|
|
||||||
|
|
||||||
onMounted(async () => {
|
|
||||||
await handleInit()
|
|
||||||
if (props.id > 0) {
|
|
||||||
await loadEncounterDetail()
|
|
||||||
}
|
|
||||||
})
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
@@ -144,9 +157,11 @@ onMounted(async () => {
|
|||||||
:seps="sepsList"
|
:seps="sepsList"
|
||||||
:participant-groups="participantGroupsList"
|
:participant-groups="participantGroupsList"
|
||||||
:specialists="specialistsTree"
|
:specialists="specialistsTree"
|
||||||
:doctor="doctorsList"
|
:doctorItems="doctorsList"
|
||||||
|
:selectedDoctor="selectedDoctor"
|
||||||
:patient="selectedPatientObject"
|
:patient="selectedPatientObject"
|
||||||
:objects="formObjects"
|
:objects="formObjects"
|
||||||
|
@on-select-doctor="getDoctorInfo"
|
||||||
@event="handleEvent"
|
@event="handleEvent"
|
||||||
@fetch="handleFetch"
|
@fetch="handleFetch"
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -70,18 +70,18 @@ export function useEncounterEntry(props: {
|
|||||||
})
|
})
|
||||||
|
|
||||||
function getListPath(): string {
|
function getListPath(): string {
|
||||||
if (props.classCode === 'ambulatory' && props.subClassCode === 'rehab') {
|
if (props.classCode === 'ambulatory') {
|
||||||
return '/rehab/encounter'
|
return '/ambulatory/encounter'
|
||||||
}
|
|
||||||
if (props.classCode === 'ambulatory' && props.subClassCode === 'reg') {
|
|
||||||
return '/outpatient/encounter'
|
|
||||||
}
|
|
||||||
if (props.classCode === 'emergency') {
|
|
||||||
return '/emergency/encounter'
|
|
||||||
}
|
|
||||||
if (props.classCode === 'inpatient') {
|
|
||||||
return '/inpatient/encounter'
|
|
||||||
}
|
}
|
||||||
|
// if (props.classCode === 'ambulatory' && props.subClassCode === 'reg') {
|
||||||
|
// return '/outpatient/encounter'
|
||||||
|
// }
|
||||||
|
// if (props.classCode === 'emergency') {
|
||||||
|
// return '/emergency/encounter'
|
||||||
|
// }
|
||||||
|
// if (props.classCode === 'inpatient') {
|
||||||
|
// return '/inpatient/encounter'
|
||||||
|
// }
|
||||||
return '/encounter'
|
return '/encounter'
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -257,11 +257,10 @@ export function useEncounterEntry(props: {
|
|||||||
|
|
||||||
async function handleFetchDoctors(subSpecialistId: string | null = null) {
|
async function handleFetchDoctors(subSpecialistId: string | null = null) {
|
||||||
try {
|
try {
|
||||||
const filterParams: any = { 'page-size': 100, includes: 'employee-Person' }
|
const filterParams: any = { 'page-size': 100, includes: 'employee-Person,unit,specialist,subspecialist' }
|
||||||
|
|
||||||
if (!subSpecialistId) {
|
if (!subSpecialistId) {
|
||||||
const doctors = await getDoctorValueLabelList(filterParams, true)
|
doctorsList.value = await getDoctorValueLabelList(filterParams, true)
|
||||||
doctorsList.value = doctors
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -273,8 +272,7 @@ export function useEncounterEntry(props: {
|
|||||||
filterParams['specialist-id'] = subSpecialistId
|
filterParams['specialist-id'] = subSpecialistId
|
||||||
}
|
}
|
||||||
|
|
||||||
const doctors = await getDoctorValueLabelList(filterParams, true)
|
doctorsList.value = await getDoctorValueLabelList(filterParams, true)
|
||||||
doctorsList.value = doctors
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Error fetching doctors:', error)
|
console.error('Error fetching doctors:', error)
|
||||||
doctorsList.value = []
|
doctorsList.value = []
|
||||||
|
|||||||
@@ -55,23 +55,29 @@ const defaultKeys: Record<string, any> = {
|
|||||||
classCode: ['ambulatory', 'emergency', 'inpatient'],
|
classCode: ['ambulatory', 'emergency', 'inpatient'],
|
||||||
unit: 'all',
|
unit: 'all',
|
||||||
},
|
},
|
||||||
|
earlyNurseryAssessment: {
|
||||||
|
id: 'early-nursery-assessment',
|
||||||
|
title: 'Pengkajian Awal Keperawatan',
|
||||||
|
classCode: ['ambulatory', 'emergency', 'inpatient'],
|
||||||
|
unit: 'all',
|
||||||
|
},
|
||||||
earlyMedicalAssessment: {
|
earlyMedicalAssessment: {
|
||||||
id: 'early-medical-assessment',
|
id: 'early-medical-assessment',
|
||||||
title: 'Pengkajian Awal Medis',
|
title: 'Pengkajian Awal Medis',
|
||||||
classCode: ['ambulatory', 'emergency', 'inpatient'],
|
classCode: ['ambulatory', 'emergency', 'inpatient'],
|
||||||
unit: 'all',
|
unit: 'all',
|
||||||
},
|
},
|
||||||
rehabMedicalAssessment: {
|
earlyMedicalRehabAssessment: {
|
||||||
id: 'rehab-medical-assessment',
|
id: 'rehab-medical-assessment',
|
||||||
title: 'Pengkajian Awal Medis Rehabilitasi Medis',
|
title: 'Pengkajian Awal Medis Rehabilitasi Medis',
|
||||||
classCode: ['ambulatory', 'emergency', 'inpatient'],
|
classCode: ['ambulatory'],
|
||||||
unit: 'rehab',
|
unit: 'rehab',
|
||||||
afterId: 'early-medical-assessment',
|
afterId: 'early-medical-assessment',
|
||||||
},
|
},
|
||||||
functionAssessment: {
|
functionAssessment: {
|
||||||
id: 'function-assessment',
|
id: 'function-assessment',
|
||||||
title: 'Asesmen Fungsi',
|
title: 'Asesmen Fungsi',
|
||||||
classCode: ['ambulatory', 'emergency', 'inpatient'],
|
classCode: ['ambulatory'],
|
||||||
unit: 'rehab',
|
unit: 'rehab',
|
||||||
afterId: 'rehab-medical-assessment',
|
afterId: 'rehab-medical-assessment',
|
||||||
},
|
},
|
||||||
@@ -102,16 +108,22 @@ const defaultKeys: Record<string, any> = {
|
|||||||
classCode: ['ambulatory', 'emergency', 'inpatient'],
|
classCode: ['ambulatory', 'emergency', 'inpatient'],
|
||||||
unit: 'all',
|
unit: 'all',
|
||||||
},
|
},
|
||||||
consent: {
|
generalConsent: {
|
||||||
id: 'consent',
|
id: 'general-consent',
|
||||||
title: 'General Consent',
|
title: 'General Consent',
|
||||||
classCode: ['ambulatory', 'emergency', 'inpatient'],
|
classCode: ['ambulatory', 'emergency', 'inpatient'],
|
||||||
unit: 'all',
|
unit: 'all',
|
||||||
},
|
},
|
||||||
patientNote: {
|
patientAmbNote: {
|
||||||
id: 'patient-note',
|
id: 'patient-amb-note',
|
||||||
title: 'CPRJ',
|
title: 'CPRJ',
|
||||||
classCode: ['ambulatory', 'emergency', 'inpatient'],
|
classCode: ['ambulatory', 'emergency'],
|
||||||
|
unit: 'all',
|
||||||
|
},
|
||||||
|
patientDevNote: {
|
||||||
|
id: 'patient-dev-note',
|
||||||
|
title: 'CPP',
|
||||||
|
classCode: ['inpatient'],
|
||||||
unit: 'all',
|
unit: 'all',
|
||||||
},
|
},
|
||||||
prescription: {
|
prescription: {
|
||||||
@@ -120,38 +132,38 @@ const defaultKeys: Record<string, any> = {
|
|||||||
classCode: ['ambulatory', 'emergency', 'inpatient'],
|
classCode: ['ambulatory', 'emergency', 'inpatient'],
|
||||||
unit: 'all',
|
unit: 'all',
|
||||||
},
|
},
|
||||||
device: {
|
deviceOrder: {
|
||||||
id: 'device-order',
|
id: 'device-order',
|
||||||
title: 'Order Alkes',
|
title: 'Order Alkes',
|
||||||
classCode: ['ambulatory', 'emergency', 'inpatient'],
|
classCode: ['ambulatory', 'emergency', 'inpatient'],
|
||||||
unit: 'all',
|
unit: 'all',
|
||||||
},
|
},
|
||||||
mcuRadiology: {
|
radiologyOrder: {
|
||||||
id: 'mcu-radiology',
|
id: 'radiology-order',
|
||||||
title: 'Order Radiologi',
|
title: 'Order Radiologi',
|
||||||
classCode: ['ambulatory', 'emergency', 'inpatient'],
|
classCode: ['ambulatory', 'emergency', 'inpatient'],
|
||||||
unit: 'all',
|
unit: 'all',
|
||||||
},
|
},
|
||||||
mcuLabPc: {
|
cpLabOrder: {
|
||||||
id: 'mcu-lab-pc',
|
id: 'cp-lab-order',
|
||||||
title: 'Order Lab PK',
|
title: 'Order Lab PK',
|
||||||
classCode: ['ambulatory', 'emergency', 'inpatient'],
|
classCode: ['ambulatory', 'emergency', 'inpatient'],
|
||||||
unit: 'all',
|
unit: 'all',
|
||||||
},
|
},
|
||||||
mcuLabMicro: {
|
microLabOrder: {
|
||||||
id: 'mcu-lab-micro',
|
id: 'micro-lab-order',
|
||||||
title: 'Order Lab Mikro',
|
title: 'Order Lab Mikro',
|
||||||
classCode: ['ambulatory', 'emergency', 'inpatient'],
|
classCode: ['ambulatory', 'emergency', 'inpatient'],
|
||||||
unit: 'all',
|
unit: 'all',
|
||||||
},
|
},
|
||||||
mcuLabPa: {
|
paLabOrder: {
|
||||||
id: 'mcu-lab-pa',
|
id: 'pa-lab-order',
|
||||||
title: 'Order Lab PA',
|
title: 'Order Lab PA',
|
||||||
classCode: ['ambulatory', 'emergency', 'inpatient'],
|
classCode: ['ambulatory', 'emergency', 'inpatient'],
|
||||||
unit: 'all',
|
unit: 'all',
|
||||||
},
|
},
|
||||||
medicalAction: {
|
actionRoomOrder: {
|
||||||
id: 'medical-action',
|
id: 'action-room-order',
|
||||||
title: 'Order Ruang Tindakan',
|
title: 'Order Ruang Tindakan',
|
||||||
classCode: ['ambulatory', 'emergency', 'inpatient'],
|
classCode: ['ambulatory', 'emergency', 'inpatient'],
|
||||||
unit: 'all',
|
unit: 'all',
|
||||||
@@ -162,21 +174,45 @@ const defaultKeys: Record<string, any> = {
|
|||||||
classCode: ['ambulatory', 'emergency', 'inpatient'],
|
classCode: ['ambulatory', 'emergency', 'inpatient'],
|
||||||
unit: 'all',
|
unit: 'all',
|
||||||
},
|
},
|
||||||
|
actionReport: {
|
||||||
|
id: 'action-report',
|
||||||
|
title: 'Laporan Tindakan',
|
||||||
|
classCode: ['ambulatory', 'emergency', 'inpatient'],
|
||||||
|
unit: 'all',
|
||||||
|
},
|
||||||
|
surgeryReport: {
|
||||||
|
id: 'surgery-report',
|
||||||
|
title: 'Laporan Operasi',
|
||||||
|
classCode: ['ambulatory', 'emergency', 'inpatient'],
|
||||||
|
unit: 'all',
|
||||||
|
},
|
||||||
|
vacsinData: {
|
||||||
|
id: 'vacsin-data',
|
||||||
|
title: 'Data Vaksin',
|
||||||
|
classCode: ['ambulatory', 'emergency', 'inpatient'],
|
||||||
|
unit: 'all',
|
||||||
|
},
|
||||||
consultation: {
|
consultation: {
|
||||||
id: 'consultation',
|
id: 'consultation',
|
||||||
title: 'Konsultasi',
|
title: 'Konsultasi',
|
||||||
classCode: ['ambulatory', 'emergency', 'inpatient'],
|
classCode: ['ambulatory', 'emergency', 'inpatient'],
|
||||||
unit: 'all',
|
unit: 'all',
|
||||||
},
|
},
|
||||||
resume: {
|
controlLetter: {
|
||||||
id: 'resume',
|
id: 'control-letter',
|
||||||
title: 'Resume',
|
title: 'Surat Kontrol',
|
||||||
classCode: ['ambulatory', 'emergency', 'inpatient'],
|
classCode: ['ambulatory', 'emergency', 'inpatient'],
|
||||||
unit: 'all',
|
unit: 'all',
|
||||||
},
|
},
|
||||||
control: {
|
inpatientLetter: {
|
||||||
id: 'control',
|
id: 'inpatient-letter',
|
||||||
title: 'Surat Kontrol',
|
title: 'SPRI',
|
||||||
|
classCode: ['ambulatory', 'emergency'],
|
||||||
|
unit: 'all',
|
||||||
|
},
|
||||||
|
refBack: {
|
||||||
|
id: 'reference-back',
|
||||||
|
title: 'PRB',
|
||||||
classCode: ['ambulatory', 'emergency', 'inpatient'],
|
classCode: ['ambulatory', 'emergency', 'inpatient'],
|
||||||
unit: 'all',
|
unit: 'all',
|
||||||
},
|
},
|
||||||
@@ -190,7 +226,19 @@ const defaultKeys: Record<string, any> = {
|
|||||||
id: 'supporting-document',
|
id: 'supporting-document',
|
||||||
title: 'Upload Dokumen Pendukung',
|
title: 'Upload Dokumen Pendukung',
|
||||||
classCode: ['ambulatory'],
|
classCode: ['ambulatory'],
|
||||||
unit: 'rehab',
|
unit: 'all',
|
||||||
|
},
|
||||||
|
resume: {
|
||||||
|
id: 'resume',
|
||||||
|
title: 'Resume',
|
||||||
|
classCode: ['ambulatory', 'emergency', 'inpatient'],
|
||||||
|
unit: 'all',
|
||||||
|
},
|
||||||
|
ambResume: {
|
||||||
|
id: 'amb-resume',
|
||||||
|
title: 'Resume Medis Rawat Jalan',
|
||||||
|
classCode: ['ambulatory', 'emergency', 'inpatient'],
|
||||||
|
unit: 'all',
|
||||||
},
|
},
|
||||||
priceList: {
|
priceList: {
|
||||||
id: 'price-list',
|
id: 'price-list',
|
||||||
@@ -244,12 +292,12 @@ export function injectComponents(id: string | number, data: EncounterListData, m
|
|||||||
label: currentKeys.earlyMedicalAssessment['title'],
|
label: currentKeys.earlyMedicalAssessment['title'],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (currentKeys?.rehabMedicalAssessment) {
|
if (currentKeys?.earlyMedicalRehabAssessment) {
|
||||||
currentKeys.rehabMedicalAssessment['component'] = EarlyMedicalRehabListAsync
|
currentKeys.earlyMedicalRehabAssessment['component'] = EarlyMedicalRehabListAsync
|
||||||
currentKeys.rehabMedicalAssessment['props'] = {
|
currentKeys.earlyMedicalRehabAssessment['props'] = {
|
||||||
encounter: data?.encounter,
|
encounter: data?.encounter,
|
||||||
type: 'early-rehab',
|
type: 'early-rehab',
|
||||||
label: currentKeys.rehabMedicalAssessment['title'],
|
label: currentKeys.earlyMedicalRehabAssessment['title'],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (currentKeys?.functionAssessment) {
|
if (currentKeys?.functionAssessment) {
|
||||||
@@ -287,44 +335,44 @@ export function injectComponents(id: string | number, data: EncounterListData, m
|
|||||||
currentKeys.educationAssessment['component'] = null
|
currentKeys.educationAssessment['component'] = null
|
||||||
currentKeys.educationAssessment['props'] = { encounter_id: id }
|
currentKeys.educationAssessment['props'] = { encounter_id: id }
|
||||||
}
|
}
|
||||||
if (currentKeys?.consent) {
|
if (currentKeys?.generalConsent) {
|
||||||
currentKeys.consent['component'] = GeneralConsentListAsync
|
currentKeys.generalConsent['component'] = GeneralConsentListAsync
|
||||||
currentKeys.consent['props'] = { encounter_id: id }
|
currentKeys.generalConsent['props'] = { encounter_id: id }
|
||||||
}
|
}
|
||||||
if (currentKeys?.patientNote) {
|
if (currentKeys?.patientAmbNote) {
|
||||||
currentKeys.patientNote['component'] = CprjAsync
|
currentKeys.patientAmbNote['component'] = CprjAsync
|
||||||
currentKeys.patientNote['props'] = { encounter_id: id }
|
currentKeys.patientAmbNote['props'] = { encounter_id: id }
|
||||||
}
|
}
|
||||||
if (currentKeys?.prescription) {
|
if (currentKeys?.prescription) {
|
||||||
currentKeys.prescription['component'] = PrescriptionAsync
|
currentKeys.prescription['component'] = PrescriptionAsync
|
||||||
currentKeys.prescription['props'] = { encounter_id: id }
|
currentKeys.prescription['props'] = { encounter_id: id }
|
||||||
}
|
}
|
||||||
if (currentKeys?.device) {
|
if (currentKeys?.deviceOrder) {
|
||||||
currentKeys.device['component'] = DeviceOrderAsync
|
currentKeys.deviceOrder['component'] = DeviceOrderAsync
|
||||||
currentKeys.device['props'] = { encounter_id: id }
|
currentKeys.deviceOrder['props'] = { encounter_id: id }
|
||||||
}
|
}
|
||||||
if (currentKeys?.mcuRadiology) {
|
if (currentKeys?.radiologyOrder) {
|
||||||
currentKeys.mcuRadiology['component'] = RadiologyAsync
|
currentKeys.radiologyOrder['component'] = RadiologyAsync
|
||||||
currentKeys.mcuRadiology['props'] = { encounter_id: id }
|
currentKeys.radiologyOrder['props'] = { encounter_id: id }
|
||||||
}
|
}
|
||||||
if (currentKeys?.mcuLabPc) {
|
if (currentKeys?.cpLabOrder) {
|
||||||
currentKeys.mcuLabPc['component'] = CpLabOrderAsync
|
currentKeys.cpLabOrder['component'] = CpLabOrderAsync
|
||||||
currentKeys.mcuLabPc['props'] = { encounter_id: id }
|
currentKeys.cpLabOrder['props'] = { encounter_id: id }
|
||||||
}
|
}
|
||||||
if (currentKeys?.mcuLabMicro) {
|
if (currentKeys?.microLabOrder) {
|
||||||
// TODO: add component for mcuLabMicro
|
// TODO: add component for microLabOrder
|
||||||
currentKeys.mcuLabMicro['component'] = null
|
currentKeys.microLabOrder['component'] = null
|
||||||
currentKeys.mcuLabMicro['props'] = { encounter_id: id }
|
currentKeys.microLabOrder['props'] = { encounter_id: id }
|
||||||
}
|
}
|
||||||
if (currentKeys?.mcuLabPa) {
|
if (currentKeys?.paLabOrder) {
|
||||||
// TODO: add component for mcuLabPa
|
// TODO: add component for paLabOrder
|
||||||
currentKeys.mcuLabPa['component'] = null
|
currentKeys.paLabOrder['component'] = null
|
||||||
currentKeys.mcuLabPa['props'] = { encounter_id: id }
|
currentKeys.paLabOrder['props'] = { encounter_id: id }
|
||||||
}
|
}
|
||||||
if (currentKeys?.medicalAction) {
|
if (currentKeys?.actionRoomOrder) {
|
||||||
// TODO: add component for medicalAction
|
// TODO: add component for actionRoomOrder
|
||||||
currentKeys.medicalAction['component'] = null
|
currentKeys.actionRoomOrder['component'] = null
|
||||||
currentKeys.medicalAction['props'] = { encounter_id: id }
|
currentKeys.actionRoomOrder['props'] = { encounter_id: id }
|
||||||
}
|
}
|
||||||
if (currentKeys?.mcuResult) {
|
if (currentKeys?.mcuResult) {
|
||||||
// TODO: add component for mcuResult
|
// TODO: add component for mcuResult
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import { type Base, genBase } from "./_base"
|
import { type Base, genBase } from "./_base"
|
||||||
import { type Employee, genEmployee } from "./employee"
|
import { type Employee, genEmployee } from "./employee"
|
||||||
|
import type { Unit } from "./unit"
|
||||||
import type { Specialist } from "./specialist"
|
import type { Specialist } from "./specialist"
|
||||||
import type { Subspecialist } from "./subspecialist"
|
import type { Subspecialist } from "./subspecialist"
|
||||||
|
|
||||||
@@ -9,10 +10,11 @@ export interface Doctor extends Base {
|
|||||||
ihs_number: string
|
ihs_number: string
|
||||||
sip_number: string
|
sip_number: string
|
||||||
code?: string
|
code?: string
|
||||||
unit_icode?: number
|
unit_code?: string
|
||||||
specialist_icode?: number
|
unit?: Unit
|
||||||
|
specialist_code?: string
|
||||||
specialist?: Specialist
|
specialist?: Specialist
|
||||||
subspecialist_icode?: number
|
subspecialist_code?: string
|
||||||
subspecialist?: Subspecialist
|
subspecialist?: Subspecialist
|
||||||
bpjs_code?: string
|
bpjs_code?: string
|
||||||
}
|
}
|
||||||
|
|||||||
+10
-7
@@ -3,6 +3,7 @@ import { type Doctor, genDoctor } from "./doctor"
|
|||||||
import { genEmployee, type Employee } from "./employee"
|
import { genEmployee, type Employee } from "./employee"
|
||||||
import type { EncounterDocument } from "./encounter-document"
|
import type { EncounterDocument } from "./encounter-document"
|
||||||
import type { InternalReference } from "./internal-reference"
|
import type { InternalReference } from "./internal-reference"
|
||||||
|
import type { Nurse } from "./nurse"
|
||||||
import { type Patient, genPatient } from "./patient"
|
import { type Patient, genPatient } from "./patient"
|
||||||
import type { Specialist } from "./specialist"
|
import type { Specialist } from "./specialist"
|
||||||
import type { Subspecialist } from "./subspecialist"
|
import type { Subspecialist } from "./subspecialist"
|
||||||
@@ -14,18 +15,20 @@ export interface Encounter {
|
|||||||
patient: Patient
|
patient: Patient
|
||||||
registeredAt: string
|
registeredAt: string
|
||||||
class_code: string
|
class_code: string
|
||||||
unit_id: number
|
unit_code: string
|
||||||
unit: Unit
|
unit: Unit
|
||||||
specialist_id?: number
|
specialist_code?: string
|
||||||
specilist?: Specialist
|
specilist?: Specialist
|
||||||
subspecialist_id?: number
|
subspecialist_code?: string
|
||||||
subspecialist?: Subspecialist
|
subspecialist?: Subspecialist
|
||||||
visitDate: string
|
visitDate: string
|
||||||
adm_employee_id: number
|
adm_employee_id: number
|
||||||
adm_employee: Employee
|
adm_employee: Employee
|
||||||
appointment_doctor_id: number
|
responsible_nurse_code?: string
|
||||||
|
responsible_nurse?: Nurse
|
||||||
|
appointment_doctor_code: string
|
||||||
appointment_doctor: Doctor
|
appointment_doctor: Doctor
|
||||||
responsible_doctor_id?: number
|
responsible_doctor_code?: string
|
||||||
responsible_doctor?: Doctor
|
responsible_doctor?: Doctor
|
||||||
refSource_name?: string
|
refSource_name?: string
|
||||||
appointment_id?: number
|
appointment_id?: number
|
||||||
@@ -49,12 +52,12 @@ export function genEncounter(): Encounter {
|
|||||||
patient: genPatient(),
|
patient: genPatient(),
|
||||||
registeredAt: '',
|
registeredAt: '',
|
||||||
class_code: '',
|
class_code: '',
|
||||||
unit_id: 0,
|
unit_code: 0,
|
||||||
unit: genUnit(),
|
unit: genUnit(),
|
||||||
visitDate: '',
|
visitDate: '',
|
||||||
adm_employee_id: 0,
|
adm_employee_id: 0,
|
||||||
adm_employee: genEmployee(),
|
adm_employee: genEmployee(),
|
||||||
appointment_doctor_id: 0,
|
appointment_doctor_code: '',
|
||||||
appointment_doctor: genDoctor(),
|
appointment_doctor: genDoctor(),
|
||||||
medicalDischargeEducation: '',
|
medicalDischargeEducation: '',
|
||||||
status_code: '',
|
status_code: '',
|
||||||
|
|||||||
@@ -2,10 +2,12 @@ import { z } from 'zod'
|
|||||||
|
|
||||||
const ERROR_MESSAGES = {
|
const ERROR_MESSAGES = {
|
||||||
required: {
|
required: {
|
||||||
doctorId: 'Dokter wajib diisi',
|
doctor_code: 'Dokter wajib diisi',
|
||||||
registerDate: 'Tanggal Daftar wajib diisi',
|
registerDate: 'Tanggal Daftar wajib diisi',
|
||||||
paymentType: 'Jenis Pembayaran wajib diisi',
|
paymentMethod_code: 'Jenis Pembayaran wajib diisi',
|
||||||
subSpecialistId: 'Subspesialis wajib diisi',
|
unit_code: 'Spesialis wajib diisi',
|
||||||
|
// specialist_code: 'Spesialis wajib diisi',
|
||||||
|
// subSpecialist_code: 'Subspesialis wajib diisi',
|
||||||
patientCategory: 'Kelompok Peserta wajib diisi',
|
patientCategory: 'Kelompok Peserta wajib diisi',
|
||||||
cardNumber: 'No. Kartu BPJS wajib diisi',
|
cardNumber: 'No. Kartu BPJS wajib diisi',
|
||||||
sepType: 'Jenis SEP wajib diisi',
|
sepType: 'Jenis SEP wajib diisi',
|
||||||
@@ -23,19 +25,19 @@ const IntegrationEncounterSchema = z
|
|||||||
medicalRecordNumber: z.string().optional(),
|
medicalRecordNumber: z.string().optional(),
|
||||||
|
|
||||||
// Visit data
|
// Visit data
|
||||||
doctorId: z
|
doctor_code: z
|
||||||
.string({ required_error: ERROR_MESSAGES.required.doctorId })
|
.string({ required_error: ERROR_MESSAGES.required.doctor_code })
|
||||||
.min(1, ERROR_MESSAGES.required.doctorId),
|
.min(1, ERROR_MESSAGES.required.doctor_code),
|
||||||
subSpecialistId: z
|
unit_code: z
|
||||||
.string({ required_error: ERROR_MESSAGES.required.subSpecialistId })
|
.string({ required_error: ERROR_MESSAGES.required.unit_code })
|
||||||
.min(1, ERROR_MESSAGES.required.subSpecialistId)
|
.min(1, ERROR_MESSAGES.required.unit_code)
|
||||||
.optional(),
|
.optional(),
|
||||||
registerDate: z
|
registerDate: z
|
||||||
.string({ required_error: ERROR_MESSAGES.required.registerDate })
|
.string({ required_error: ERROR_MESSAGES.required.registerDate })
|
||||||
.min(1, ERROR_MESSAGES.required.registerDate),
|
.min(1, ERROR_MESSAGES.required.registerDate),
|
||||||
paymentType: z
|
paymentMethod_code: z
|
||||||
.string({ required_error: ERROR_MESSAGES.required.paymentType })
|
.string({ required_error: ERROR_MESSAGES.required.paymentMethod_code })
|
||||||
.min(1, ERROR_MESSAGES.required.paymentType),
|
.min(1, ERROR_MESSAGES.required.paymentMethod_code),
|
||||||
|
|
||||||
// BPJS related fields
|
// BPJS related fields
|
||||||
patientCategory: z
|
patientCategory: z
|
||||||
@@ -76,7 +78,7 @@ const IntegrationEncounterSchema = z
|
|||||||
.refine(
|
.refine(
|
||||||
(data) => {
|
(data) => {
|
||||||
// If payment type is jkn, then patient category is required
|
// If payment type is jkn, then patient category is required
|
||||||
if (data.paymentType === 'jkn') {
|
if (data.paymentMethod_code === 'jkn') {
|
||||||
return data.patientCategory && data.patientCategory.trim() !== ''
|
return data.patientCategory && data.patientCategory.trim() !== ''
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
@@ -89,7 +91,7 @@ const IntegrationEncounterSchema = z
|
|||||||
.refine(
|
.refine(
|
||||||
(data) => {
|
(data) => {
|
||||||
// If payment type is jkn, then card number is required
|
// If payment type is jkn, then card number is required
|
||||||
if (data.paymentType === 'jkn') {
|
if (data.paymentMethod_code === 'jkn') {
|
||||||
return data.cardNumber && data.cardNumber.trim() !== ''
|
return data.cardNumber && data.cardNumber.trim() !== ''
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
@@ -102,7 +104,7 @@ const IntegrationEncounterSchema = z
|
|||||||
.refine(
|
.refine(
|
||||||
(data) => {
|
(data) => {
|
||||||
// If payment type is jkn, then SEP type is required
|
// If payment type is jkn, then SEP type is required
|
||||||
if (data.paymentType === 'jkn') {
|
if (data.paymentMethod_code === 'jkn') {
|
||||||
return data.sepType && data.sepType.trim() !== ''
|
return data.sepType && data.sepType.trim() !== ''
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
@@ -115,7 +117,7 @@ const IntegrationEncounterSchema = z
|
|||||||
.refine(
|
.refine(
|
||||||
(data) => {
|
(data) => {
|
||||||
// If payment type is jkn and SEP type is selected, then SEP number is required
|
// If payment type is jkn and SEP type is selected, then SEP number is required
|
||||||
if (data.paymentType === 'jkn' && data.sepType && data.sepType.trim() !== '') {
|
if (data.paymentMethod_code === 'jkn' && data.sepType && data.sepType.trim() !== '') {
|
||||||
return data.sepNumber && data.sepNumber.trim() !== ''
|
return data.sepNumber && data.sepNumber.trim() !== ''
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
|
|||||||
@@ -13,8 +13,8 @@ export function getList(params: any = null) {
|
|||||||
return base.getList(path, params, name)
|
return base.getList(path, params, name)
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getDetail(id: number | string) {
|
export function getDetail(id: number | string, params?: any) {
|
||||||
return base.getDetail(path, id, name)
|
return base.getDetail(path, id, name, params)
|
||||||
}
|
}
|
||||||
|
|
||||||
export function update(id: number | string, data: any) {
|
export function update(id: number | string, data: any) {
|
||||||
|
|||||||
Reference in New Issue
Block a user