Merge pull request #194 from dikstub-rssa/feat/page-cleaning

Feat/page cleaning
This commit is contained in:
Andsky
2025-12-02 10:02:35 +07:00
committed by GitHub
11 changed files with 926 additions and 299 deletions
+185 -149
View File
@@ -1,43 +1,57 @@
<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 * as DE from '~/components/pub/my-ui/doc-entry'
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 * as CB from '~/components/pub/my-ui/combobox'
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'
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<{
isLoading?: boolean
isReadonly?: boolean
isSepValid?: boolean
isCheckingSep?: boolean
doctor?: any[]
subSpecialist?: any[]
specialists?: TreeItem[]
payments: any[]
doctorItems?: CB.Item[]
selectedDoctor: Doctor
// subSpecialist?: any[]
// specialists?: TreeItem[]
// paymentMethods: PaymentMethodCode[]
participantGroups?: any[]
seps: any[]
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<{
(e: 'onSelectDoctor', code: string): void
(e: 'event', menu: string, value?: any): void
(e: 'fetch', value?: any): void
}>()
@@ -48,10 +62,10 @@ const { handleSubmit, errors, defineField, meta } = useForm<IntegrationEncounter
})
// Bind fields and extract attrs
const [doctorId, doctorIdAttrs] = defineField('doctorId')
const [subSpecialistId, subSpecialistIdAttrs] = defineField('subSpecialistId')
const [doctorCode, doctorCodeAttrs] = defineField('doctor_code')
const [unitCode, unitCodeAttrs] = defineField('unit_code')
const [registerDate, registerDateAttrs] = defineField('registerDate')
const [paymentType, paymentTypeAttrs] = defineField('paymentType')
const [paymentMethodCode, paymentMethodCodeAttrs] = defineField('paymentMethod_code')
const [patientCategory, patientCategoryAttrs] = defineField('patientCategory')
const [cardNumber, cardNumberAttrs] = defineField('cardNumber')
const [sepType, sepTypeAttrs] = defineField('sepType')
@@ -68,30 +82,50 @@ const isReadonly = props.isReadonly !== undefined ? props.isReadonly : false
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]
})
// Unit, specialist, subspecialist
const unitFullName = ref('')
watch(() => props.selectedDoctor, (doctor) => {
unitFullName.value = doctor.subspecialist?.name ??
doctor.specialist?.name ??
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> {
console.log('onFetchChildren', parentId)
}
// 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 })
}
})
// watch(subSpecialistCode, async (newValue) => {
// if (newValue) {
// console.log('SubSpecialist changed:', newValue)
// // Reset doctor selection
// doctorCode.value = ''
// // Emit fetch event to parent
// emit('fetch', { subSpecialistCode: newValue })
// }
// })
// Debounced SEP number watcher: emit change only after user stops typing
const debouncedSepNumber = refDebounced(sepNumber, 500)
@@ -100,25 +134,25 @@ watch(debouncedSepNumber, (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.objects,
// (objects) => {
// if (objects && Object.keys(objects).length > 0) {
// patientName.value = objects?.patientName || ''
// nationalIdentity.value = objects?.nationalIdentity || ''
// medicalRecordNumber.value = objects?.medicalRecordNumber || ''
// doctorCode.value = objects?.doctorCode || ''
// subSpecialistCode.value = objects?.subSpecialistCode || ''
// registerDate.value = objects?.registerDate || ''
// paymentMethodCode.value = objects?.paymentMethodCode || ''
// patientCategory.value = objects?.patientCategory || ''
// cardNumber.value = objects?.cardNumber || ''
// sepType.value = objects?.sepType || ''
// sepNumber.value = objects?.sepNumber || ''
// }
// },
// { deep: true, immediate: true },
// )
watch(
() => props.patient,
@@ -136,11 +170,11 @@ watch(
function onAddSep() {
const formValues = {
patientId: patientId.value || '',
doctorCode: doctorId.value,
subSpecialistCode: subSpecialistId.value,
doctorCode: doctorCode.value,
// subSpecialistCode: subSpecialistCode.value,
registerDate: registerDate.value,
cardNumber: cardNumber.value,
paymentType: paymentType.value,
paymentMethodCode: paymentMethodCode.value,
sepType: sepType.value
}
emit('event', 'add-sep', formValues)
@@ -158,10 +192,10 @@ 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,
doctorCode: doctorCode.value,
// subSpecialistCode: subSpecialistCode.value,
registerDate: registerDate.value,
paymentType: paymentType.value,
paymentMethodCode: paymentMethodCode.value,
})
console.log('🔵 Form errors:', errors.value)
console.log('🔵 Form meta:', meta.value)
@@ -231,149 +265,151 @@ defineExpose({
</div>
</div>
<Block
<DE.Block
labelSize="thin"
class="!pt-0"
:colCount="3"
:cellFlex="false"
>
<Cell>
<Label height="compact">Nama Pasien</Label>
<Field :errMessage="errors.patientName">
<DE.Cell>
<DE.Label height="compact">Nama Pasien</DE.Label>
<DE.Field :errMessage="errors.patientName">
<Input
id="patientName"
v-model="patientName"
v-bind="patientNameAttrs"
:disabled="true"
/>
</Field>
</Cell>
</DE.Field>
</DE.Cell>
<Cell>
<Label height="compact">NIK</Label>
<Field :errMessage="errors.nationalIdentity">
<DE.Cell>
<DE.Label height="compact">NIK</DE.Label>
<DE.Field :errMessage="errors.nationalIdentity">
<Input
id="nationalIdentity"
v-model="nationalIdentity"
v-bind="nationalIdentityAttrs"
:disabled="true"
/>
</Field>
</Cell>
</DE.Field>
</DE.Cell>
<Cell>
<Label height="compact">No. RM</Label>
<Field :errMessage="errors.medicalRecordNumber">
<DE.Cell>
<DE.Label height="compact">No. RM</DE.Label>
<DE.Field :errMessage="errors.medicalRecordNumber">
<Input
id="medicalRecordNumber"
v-model="medicalRecordNumber"
v-bind="medicalRecordNumberAttrs"
:disabled="true"
/>
</Field>
</Cell>
</Block>
</DE.Field>
</DE.Cell>
</DE.Block>
<hr />
<!-- Data Kunjungan -->
<h3 class="text-lg font-semibold">Data Kunjungan</h3>
<Block
<DE.Block
labelSize="thin"
class="!pt-0"
:colCount="3"
:cellFlex="false"
>
<Cell>
<Label height="compact">
<DE.Cell>
<DE.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"
</DE.Label>
<DE.Field :errMessage="errors.doctor_code">
<CB.Combobox
id="doctorCode"
v-model="doctorCode"
v-bind="doctorCodeAttrs"
:items="[...defaultCBItems, ...doctorItems]"
:is-disabled="isLoading || isReadonly"
placeholder="Pilih Dokter"
search-placeholder="Cari Dokter"
empty-message="Dokter tidak ditemukan"
@update:model-value="(value) => emit('onSelectDoctor', value)"
/>
</Field>
</Cell>
</DE.Field>
</DE.Cell>
<Cell>
<Label height="compact">
<DE.Cell>
<DE.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"
</DE.Label>
<DE.Field :errMessage="errors.unit_code">
<Input :value="unitFullName"/>
<!-- <TreeSelect
id="subSpecialistCode"
v-model="subSpecialistCode"
v-bind="subSpecialistCodeAttrs"
:data="specialists || []"
:on-fetch-children="onFetchChildren"
/>
</Field>
</Cell>
</Block>
/> -->
</DE.Field>
</DE.Cell>
</DE.Block>
<Block
<DE.Block
labelSize="thin"
class="!pt-0"
:colCount="3"
:cellFlex="false"
>
<Cell>
<Label height="compact">
<DE.Cell>
<DE.Label height="compact">
Tanggal Daftar
<span class="text-red-500">*</span>
</Label>
<Field :errMessage="errors.registerDate">
</DE.Label>
<DE.Field :errMessage="errors.registerDate">
<DatepickerSingle
id="registerDate"
v-model="registerDate"
v-bind="registerDateAttrs"
placeholder="Pilih tanggal"
/>
</Field>
</Cell>
</DE.Field>
</DE.Cell>
<Cell>
<Label height="compact">
<DE.Cell>
<DE.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"
</DE.Label>
<DE.Field :errMessage="errors.paymentMethod_code">
<CB.Combobox
id="paymentMethodCode"
v-model="paymentMethodCode"
v-bind="paymentMethodCodeAttrs"
:items="paymentMethodItems"
:disabled="isLoading || isReadonly"
placeholder="Pilih Jenis Pembayaran"
/>
</Field>
</Cell>
</Block>
</DE.Field>
</DE.Cell>
</DE.Block>
<!-- BPJS Fields (conditional) -->
<template v-if="isJKNPayment">
<Block
<DE.Block
labelSize="thin"
class="!pt-0"
:colCount="3"
:cellFlex="false"
>
<Cell>
<Label height="compact">
<DE.Cell>
<DE.Label height="compact">
Kelompok Peserta
<span class="text-red-500">*</span>
</Label>
<Field :errMessage="errors.patientCategory">
</DE.Label>
<DE.Field :errMessage="errors.patientCategory">
<Select
id="patientCategory"
v-model="patientCategory"
@@ -382,15 +418,15 @@ defineExpose({
:disabled="isLoading || isReadonly"
placeholder="Pilih Kelompok Peserta"
/>
</Field>
</Cell>
</DE.Field>
</DE.Cell>
<Cell>
<Label height="compact">
<DE.Cell>
<DE.Label height="compact">
No. Kartu BPJS
<span class="text-red-500">*</span>
</Label>
<Field :errMessage="errors.cardNumber">
</DE.Label>
<DE.Field :errMessage="errors.cardNumber">
<Input
id="cardNumber"
v-model="cardNumber"
@@ -398,15 +434,15 @@ defineExpose({
:disabled="isLoading || isReadonly"
placeholder="Masukkan nomor kartu BPJS"
/>
</Field>
</Cell>
</DE.Field>
</DE.Cell>
<Cell>
<Label height="compact">
<DE.Cell>
<DE.Label height="compact">
Jenis SEP
<span class="text-red-500">*</span>
</Label>
<Field :errMessage="errors.sepType">
</DE.Label>
<DE.Field :errMessage="errors.sepType">
<Select
id="sepType"
v-model="sepType"
@@ -415,22 +451,22 @@ defineExpose({
:disabled="isLoading || isReadonly"
placeholder="Pilih Jenis SEP"
/>
</Field>
</Cell>
</Block>
</DE.Field>
</DE.Cell>
</DE.Block>
<Block
<DE.Block
labelSize="thin"
class="!pt-0"
:colCount="3"
:cellFlex="false"
>
<Cell>
<Label height="compact">
<DE.Cell>
<DE.Label height="compact">
No. SEP
<span class="text-red-500">*</span>
</Label>
<Field :errMessage="errors.sepNumber">
</DE.Label>
<DE.Field :errMessage="errors.sepNumber">
<div class="flex gap-2">
<Input
id="sepNumber"
@@ -474,8 +510,8 @@ defineExpose({
/>
</Button>
</div>
</Field>
</Cell>
</DE.Field>
</DE.Cell>
<FileUpload
field-name="sepFile"
@@ -492,7 +528,7 @@ defineExpose({
:accept="['pdf', 'jpg', 'png']"
:max-size-mb="1"
/>
</Block>
</DE.Block>
</template>
</form>
</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>
+40 -16
View File
@@ -7,17 +7,37 @@ const props = defineProps<{
data: Encounter
}>()
let address = ref('')
if (props.data.patient.person.addresses) {
address.value = props.data.patient.person.addresses.map((a) => a.address).join(', ')
}
const addressText = computed(() => {
if (props.data.patient.person.addresses && props.data.patient.person.addresses.length > 0) {
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) {
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) {
dpjp.value = props.data.appointment_doctor.employee.person.name
dpjpText.value = props.data.appointment_doctor.employee.person.name
}
</script>
@@ -31,7 +51,7 @@ if (props.data.responsible_doctor) {
<div>
<DE.Block mode="preview">
<DE.Cell>
<DE.Label class="font-semibold">No. RM</DE.Label>
<DE.Label class="font-semibold">Tgl. Lahir</DE.Label>
<DE.Colon />
<DE.Field>
{{ 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.Colon />
<DE.Field>
<div v-html="address"></div>
{{ addressText }}
</DE.Field>
</DE.Cell>
</DE.Block>
@@ -70,7 +90,7 @@ if (props.data.responsible_doctor) {
</DE.Field>
</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.Field>
{{ data.unit?.name }}
@@ -84,17 +104,21 @@ if (props.data.responsible_doctor) {
<DE.Label position="dynamic" class="font-semibold">DPJP</DE.Label>
<DE.Colon />
<DE.Field>
{{ dpjp }}
{{ dpjpText }}
</DE.Field>
</DE.Cell>
<DE.Cell>
<DE.Label
position="dynamic"
class="!text-base font-semibold 2xl:!text-lg"
>
<DE.Label position="dynamic" class="font-semibold">Pembayaran</DE.Label>
<DE.Colon />
<DE.Field>
{{ paymentMethodText }}
</DE.Field>
</DE.Cell>
<DE.Cell>
<DE.Label position="dynamic" class="!text-base !font-semibold 2xl:!text-lg">
Billing
</DE.Label>
<DE.Colon class="pt-1" />
<DE.Colon class="pt-1"/>
<DE.Field class="text-base 2xl:text-lg">
Rp. 000.000
<!-- {{ data }} -->
+38 -23
View File
@@ -8,8 +8,11 @@ import AppViewPatient from '~/components/app/patient/view-patient.vue'
import { refDebounced } from '@vueuse/core'
// Handlers
import { getDetail as getDoctorDetail } from '~/services/doctor.service'
import { useEncounterEntry } from '~/handlers/encounter-entry.handler'
import { genDoctor, type Doctor } from '~/models/doctor'
// Props
const props = defineProps<{
id: number
classCode?: 'ambulatory' | 'emergency' | 'inpatient' | 'outpatient'
@@ -54,7 +57,33 @@ const {
} = useEncounterEntry(props)
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() {
selectedPatientObject.value = null
setTimeout(() => {
@@ -100,29 +129,13 @@ async function handleEvent(menu: string, value?: any) {
}
}
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()
async function getDoctorInfo(value: string) {
const resp = await getDoctorDetail(value, { includes: 'unit,specialist,subspecialist'})
if (resp.success) {
selectedDoctor.value = resp.body.data
// console.log(selectedDoctor.value)
}
})
}
</script>
<template>
@@ -144,9 +157,11 @@ onMounted(async () => {
:seps="sepsList"
:participant-groups="participantGroupsList"
:specialists="specialistsTree"
:doctor="doctorsList"
:doctorItems="doctorsList"
:selectedDoctor="selectedDoctor"
:patient="selectedPatientObject"
:objects="formObjects"
@on-select-doctor="getDoctorInfo"
@event="handleEvent"
@fetch="handleFetch"
/>
+14 -16
View File
@@ -70,18 +70,18 @@ export function useEncounterEntry(props: {
})
function getListPath(): string {
if (props.classCode === 'ambulatory' && props.subClassCode === 'rehab') {
return '/rehab/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') {
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'
// }
return '/encounter'
}
@@ -257,11 +257,10 @@ export function useEncounterEntry(props: {
async function handleFetchDoctors(subSpecialistId: string | null = null) {
try {
const filterParams: any = { 'page-size': 100, includes: 'employee-Person' }
const filterParams: any = { 'page-size': 100, includes: 'employee-Person,unit,specialist,subspecialist' }
if (!subSpecialistId) {
const doctors = await getDoctorValueLabelList(filterParams, true)
doctorsList.value = doctors
doctorsList.value = await getDoctorValueLabelList(filterParams, true)
return
}
@@ -273,8 +272,7 @@ export function useEncounterEntry(props: {
filterParams['specialist-id'] = subSpecialistId
}
const doctors = await getDoctorValueLabelList(filterParams, true)
doctorsList.value = doctors
doctorsList.value = await getDoctorValueLabelList(filterParams, true)
} catch (error) {
console.error('Error fetching doctors:', error)
doctorsList.value = []
+105 -57
View File
@@ -55,23 +55,29 @@ const defaultKeys: Record<string, any> = {
classCode: ['ambulatory', 'emergency', 'inpatient'],
unit: 'all',
},
earlyNurseryAssessment: {
id: 'early-nursery-assessment',
title: 'Pengkajian Awal Keperawatan',
classCode: ['ambulatory', 'emergency', 'inpatient'],
unit: 'all',
},
earlyMedicalAssessment: {
id: 'early-medical-assessment',
title: 'Pengkajian Awal Medis',
classCode: ['ambulatory', 'emergency', 'inpatient'],
unit: 'all',
},
rehabMedicalAssessment: {
earlyMedicalRehabAssessment: {
id: 'rehab-medical-assessment',
title: 'Pengkajian Awal Medis Rehabilitasi Medis',
classCode: ['ambulatory', 'emergency', 'inpatient'],
classCode: ['ambulatory'],
unit: 'rehab',
afterId: 'early-medical-assessment',
},
functionAssessment: {
id: 'function-assessment',
title: 'Asesmen Fungsi',
classCode: ['ambulatory', 'emergency', 'inpatient'],
classCode: ['ambulatory'],
unit: 'rehab',
afterId: 'rehab-medical-assessment',
},
@@ -102,16 +108,22 @@ const defaultKeys: Record<string, any> = {
classCode: ['ambulatory', 'emergency', 'inpatient'],
unit: 'all',
},
consent: {
id: 'consent',
generalConsent: {
id: 'general-consent',
title: 'General Consent',
classCode: ['ambulatory', 'emergency', 'inpatient'],
unit: 'all',
},
patientNote: {
id: 'patient-note',
patientAmbNote: {
id: 'patient-amb-note',
title: 'CPRJ',
classCode: ['ambulatory', 'emergency', 'inpatient'],
classCode: ['ambulatory', 'emergency'],
unit: 'all',
},
patientDevNote: {
id: 'patient-dev-note',
title: 'CPP',
classCode: ['inpatient'],
unit: 'all',
},
prescription: {
@@ -120,38 +132,38 @@ const defaultKeys: Record<string, any> = {
classCode: ['ambulatory', 'emergency', 'inpatient'],
unit: 'all',
},
device: {
deviceOrder: {
id: 'device-order',
title: 'Order Alkes',
classCode: ['ambulatory', 'emergency', 'inpatient'],
unit: 'all',
},
mcuRadiology: {
id: 'mcu-radiology',
radiologyOrder: {
id: 'radiology-order',
title: 'Order Radiologi',
classCode: ['ambulatory', 'emergency', 'inpatient'],
unit: 'all',
},
mcuLabPc: {
id: 'mcu-lab-pc',
cpLabOrder: {
id: 'cp-lab-order',
title: 'Order Lab PK',
classCode: ['ambulatory', 'emergency', 'inpatient'],
unit: 'all',
},
mcuLabMicro: {
id: 'mcu-lab-micro',
microLabOrder: {
id: 'micro-lab-order',
title: 'Order Lab Mikro',
classCode: ['ambulatory', 'emergency', 'inpatient'],
unit: 'all',
},
mcuLabPa: {
id: 'mcu-lab-pa',
paLabOrder: {
id: 'pa-lab-order',
title: 'Order Lab PA',
classCode: ['ambulatory', 'emergency', 'inpatient'],
unit: 'all',
},
medicalAction: {
id: 'medical-action',
actionRoomOrder: {
id: 'action-room-order',
title: 'Order Ruang Tindakan',
classCode: ['ambulatory', 'emergency', 'inpatient'],
unit: 'all',
@@ -162,21 +174,45 @@ const defaultKeys: Record<string, any> = {
classCode: ['ambulatory', 'emergency', 'inpatient'],
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: {
id: 'consultation',
title: 'Konsultasi',
classCode: ['ambulatory', 'emergency', 'inpatient'],
unit: 'all',
},
resume: {
id: 'resume',
title: 'Resume',
controlLetter: {
id: 'control-letter',
title: 'Surat Kontrol',
classCode: ['ambulatory', 'emergency', 'inpatient'],
unit: 'all',
},
control: {
id: 'control',
title: 'Surat Kontrol',
inpatientLetter: {
id: 'inpatient-letter',
title: 'SPRI',
classCode: ['ambulatory', 'emergency'],
unit: 'all',
},
refBack: {
id: 'reference-back',
title: 'PRB',
classCode: ['ambulatory', 'emergency', 'inpatient'],
unit: 'all',
},
@@ -190,7 +226,19 @@ const defaultKeys: Record<string, any> = {
id: 'supporting-document',
title: 'Upload Dokumen Pendukung',
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: {
id: 'price-list',
@@ -244,12 +292,12 @@ export function injectComponents(id: string | number, data: EncounterListData, m
label: currentKeys.earlyMedicalAssessment['title'],
}
}
if (currentKeys?.rehabMedicalAssessment) {
currentKeys.rehabMedicalAssessment['component'] = EarlyMedicalRehabListAsync
currentKeys.rehabMedicalAssessment['props'] = {
if (currentKeys?.earlyMedicalRehabAssessment) {
currentKeys.earlyMedicalRehabAssessment['component'] = EarlyMedicalRehabListAsync
currentKeys.earlyMedicalRehabAssessment['props'] = {
encounter: data?.encounter,
type: 'early-rehab',
label: currentKeys.rehabMedicalAssessment['title'],
label: currentKeys.earlyMedicalRehabAssessment['title'],
}
}
if (currentKeys?.functionAssessment) {
@@ -287,44 +335,44 @@ export function injectComponents(id: string | number, data: EncounterListData, m
currentKeys.educationAssessment['component'] = null
currentKeys.educationAssessment['props'] = { encounter_id: id }
}
if (currentKeys?.consent) {
currentKeys.consent['component'] = GeneralConsentListAsync
currentKeys.consent['props'] = { encounter_id: id }
if (currentKeys?.generalConsent) {
currentKeys.generalConsent['component'] = GeneralConsentListAsync
currentKeys.generalConsent['props'] = { encounter_id: id }
}
if (currentKeys?.patientNote) {
currentKeys.patientNote['component'] = CprjAsync
currentKeys.patientNote['props'] = { encounter_id: id }
if (currentKeys?.patientAmbNote) {
currentKeys.patientAmbNote['component'] = CprjAsync
currentKeys.patientAmbNote['props'] = { encounter_id: id }
}
if (currentKeys?.prescription) {
currentKeys.prescription['component'] = PrescriptionAsync
currentKeys.prescription['props'] = { encounter_id: id }
}
if (currentKeys?.device) {
currentKeys.device['component'] = DeviceOrderAsync
currentKeys.device['props'] = { encounter_id: id }
if (currentKeys?.deviceOrder) {
currentKeys.deviceOrder['component'] = DeviceOrderAsync
currentKeys.deviceOrder['props'] = { encounter_id: id }
}
if (currentKeys?.mcuRadiology) {
currentKeys.mcuRadiology['component'] = RadiologyAsync
currentKeys.mcuRadiology['props'] = { encounter_id: id }
if (currentKeys?.radiologyOrder) {
currentKeys.radiologyOrder['component'] = RadiologyAsync
currentKeys.radiologyOrder['props'] = { encounter_id: id }
}
if (currentKeys?.mcuLabPc) {
currentKeys.mcuLabPc['component'] = CpLabOrderAsync
currentKeys.mcuLabPc['props'] = { encounter_id: id }
if (currentKeys?.cpLabOrder) {
currentKeys.cpLabOrder['component'] = CpLabOrderAsync
currentKeys.cpLabOrder['props'] = { encounter_id: id }
}
if (currentKeys?.mcuLabMicro) {
// TODO: add component for mcuLabMicro
currentKeys.mcuLabMicro['component'] = null
currentKeys.mcuLabMicro['props'] = { encounter_id: id }
if (currentKeys?.microLabOrder) {
// TODO: add component for microLabOrder
currentKeys.microLabOrder['component'] = null
currentKeys.microLabOrder['props'] = { encounter_id: id }
}
if (currentKeys?.mcuLabPa) {
// TODO: add component for mcuLabPa
currentKeys.mcuLabPa['component'] = null
currentKeys.mcuLabPa['props'] = { encounter_id: id }
if (currentKeys?.paLabOrder) {
// TODO: add component for paLabOrder
currentKeys.paLabOrder['component'] = null
currentKeys.paLabOrder['props'] = { encounter_id: id }
}
if (currentKeys?.medicalAction) {
// TODO: add component for medicalAction
currentKeys.medicalAction['component'] = null
currentKeys.medicalAction['props'] = { encounter_id: id }
if (currentKeys?.actionRoomOrder) {
// TODO: add component for actionRoomOrder
currentKeys.actionRoomOrder['component'] = null
currentKeys.actionRoomOrder['props'] = { encounter_id: id }
}
if (currentKeys?.mcuResult) {
// TODO: add component for mcuResult
+5 -3
View File
@@ -1,5 +1,6 @@
import { type Base, genBase } from "./_base"
import { type Employee, genEmployee } from "./employee"
import type { Unit } from "./unit"
import type { Specialist } from "./specialist"
import type { Subspecialist } from "./subspecialist"
@@ -9,10 +10,11 @@ export interface Doctor extends Base {
ihs_number: string
sip_number: string
code?: string
unit_icode?: number
specialist_icode?: number
unit_code?: string
unit?: Unit
specialist_code?: string
specialist?: Specialist
subspecialist_icode?: number
subspecialist_code?: string
subspecialist?: Subspecialist
bpjs_code?: string
}
+10 -7
View File
@@ -3,6 +3,7 @@ import { type Doctor, genDoctor } from "./doctor"
import { genEmployee, type Employee } from "./employee"
import type { EncounterDocument } from "./encounter-document"
import type { InternalReference } from "./internal-reference"
import type { Nurse } from "./nurse"
import { type Patient, genPatient } from "./patient"
import type { Specialist } from "./specialist"
import type { Subspecialist } from "./subspecialist"
@@ -14,18 +15,20 @@ export interface Encounter {
patient: Patient
registeredAt: string
class_code: string
unit_id: number
unit_code: string
unit: Unit
specialist_id?: number
specialist_code?: string
specilist?: Specialist
subspecialist_id?: number
subspecialist_code?: string
subspecialist?: Subspecialist
visitDate: string
adm_employee_id: number
adm_employee: Employee
appointment_doctor_id: number
responsible_nurse_code?: string
responsible_nurse?: Nurse
appointment_doctor_code: string
appointment_doctor: Doctor
responsible_doctor_id?: number
responsible_doctor_code?: string
responsible_doctor?: Doctor
refSource_name?: string
appointment_id?: number
@@ -49,12 +52,12 @@ export function genEncounter(): Encounter {
patient: genPatient(),
registeredAt: '',
class_code: '',
unit_id: 0,
unit_code: 0,
unit: genUnit(),
visitDate: '',
adm_employee_id: 0,
adm_employee: genEmployee(),
appointment_doctor_id: 0,
appointment_doctor_code: '',
appointment_doctor: genDoctor(),
medicalDischargeEducation: '',
status_code: '',
+18 -16
View File
@@ -2,10 +2,12 @@ import { z } from 'zod'
const ERROR_MESSAGES = {
required: {
doctorId: 'Dokter wajib diisi',
doctor_code: 'Dokter wajib diisi',
registerDate: 'Tanggal Daftar wajib diisi',
paymentType: 'Jenis Pembayaran wajib diisi',
subSpecialistId: 'Subspesialis wajib diisi',
paymentMethod_code: 'Jenis Pembayaran wajib diisi',
unit_code: 'Spesialis wajib diisi',
// specialist_code: 'Spesialis wajib diisi',
// subSpecialist_code: 'Subspesialis wajib diisi',
patientCategory: 'Kelompok Peserta wajib diisi',
cardNumber: 'No. Kartu BPJS wajib diisi',
sepType: 'Jenis SEP wajib diisi',
@@ -23,19 +25,19 @@ const IntegrationEncounterSchema = z
medicalRecordNumber: z.string().optional(),
// Visit data
doctorId: z
.string({ required_error: ERROR_MESSAGES.required.doctorId })
.min(1, ERROR_MESSAGES.required.doctorId),
subSpecialistId: z
.string({ required_error: ERROR_MESSAGES.required.subSpecialistId })
.min(1, ERROR_MESSAGES.required.subSpecialistId)
doctor_code: z
.string({ required_error: ERROR_MESSAGES.required.doctor_code })
.min(1, ERROR_MESSAGES.required.doctor_code),
unit_code: z
.string({ required_error: ERROR_MESSAGES.required.unit_code })
.min(1, ERROR_MESSAGES.required.unit_code)
.optional(),
registerDate: z
.string({ required_error: ERROR_MESSAGES.required.registerDate })
.min(1, ERROR_MESSAGES.required.registerDate),
paymentType: z
.string({ required_error: ERROR_MESSAGES.required.paymentType })
.min(1, ERROR_MESSAGES.required.paymentType),
paymentMethod_code: z
.string({ required_error: ERROR_MESSAGES.required.paymentMethod_code })
.min(1, ERROR_MESSAGES.required.paymentMethod_code),
// BPJS related fields
patientCategory: z
@@ -76,7 +78,7 @@ const IntegrationEncounterSchema = z
.refine(
(data) => {
// 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 true
@@ -89,7 +91,7 @@ const IntegrationEncounterSchema = z
.refine(
(data) => {
// 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 true
@@ -102,7 +104,7 @@ const IntegrationEncounterSchema = z
.refine(
(data) => {
// 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 true
@@ -115,7 +117,7 @@ const IntegrationEncounterSchema = z
.refine(
(data) => {
// 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 true
+2 -2
View File
@@ -13,8 +13,8 @@ export function getList(params: any = null) {
return base.getList(path, params, name)
}
export function getDetail(id: number | string) {
return base.getDetail(path, id, name)
export function getDetail(id: number | string, params?: any) {
return base.getDetail(path, id, name, params)
}
export function update(id: number | string, data: any) {