1164 lines
36 KiB
Vue
1164 lines
36 KiB
Vue
<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 { RadioGroup, RadioGroupItem } from '~/components/pub/ui/radio-group'
|
|
import { Textarea } from '~/components/pub/ui/textarea'
|
|
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'
|
|
|
|
// Types
|
|
import { IntegrationBpjsSchema, type IntegrationBpjsFormData } from '~/schemas/integration-bpjs.schema'
|
|
import type { TreeItem } from '~/components/pub/my-ui/select-tree/type'
|
|
|
|
// Helpers
|
|
import { watch } from 'vue'
|
|
import { toTypedSchema } from '@vee-validate/zod'
|
|
import { useForm } from 'vee-validate'
|
|
import { refDebounced } from '@vueuse/core'
|
|
|
|
const props = defineProps<{
|
|
mode?: string
|
|
isLoading?: boolean
|
|
isReadonly?: boolean
|
|
isService?: boolean
|
|
isShowPatient?: boolean
|
|
doctors: any[]
|
|
diagnoses: any[]
|
|
facilitiesFrom: any[]
|
|
facilitiesTo: any[]
|
|
serviceTypes: any[]
|
|
registerMethods: any[]
|
|
accidents: any[]
|
|
purposes: any[]
|
|
procedures: any[]
|
|
assessments: any[]
|
|
supportCodes: any[]
|
|
classLevels: any[]
|
|
classLevelUpgrades: any[]
|
|
classPaySources: any[]
|
|
provinces: any[]
|
|
cities: any[]
|
|
districts: any[]
|
|
specialists?: TreeItem[]
|
|
objects?: any
|
|
values?: any
|
|
}>()
|
|
|
|
const emit = defineEmits<{
|
|
(e: 'event', menu: string, value?: any): void
|
|
(e: 'fetch', value?: any): void
|
|
}>()
|
|
|
|
// Validation schema (moved to shared file)
|
|
const { handleSubmit, errors, defineField } = useForm<IntegrationBpjsFormData>({
|
|
validationSchema: toTypedSchema(IntegrationBpjsSchema),
|
|
})
|
|
|
|
// Bind fields and extract attrs for consistent Field pattern
|
|
const [sepDate, sepDateAttrs] = defineField('sepDate')
|
|
const [serviceType, serviceTypeAttrs] = defineField('serviceType')
|
|
const [admissionType, admissionTypeAttrs] = defineField('admissionType')
|
|
const [cardNumber, cardNumberAttrs] = defineField('cardNumber')
|
|
const [nationalId, nationalIdAttrs] = defineField('nationalId')
|
|
const [medicalRecordNumber, medicalRecordNumberAttrs] = defineField('medicalRecordNumber')
|
|
const [patientName, patientNameAttrs] = defineField('patientName')
|
|
const [phoneNumber, phoneNumberAttrs] = defineField('phoneNumber')
|
|
const [referralLetterNumber, referralLetterNumberAttrs] = defineField('referralLetterNumber')
|
|
const [referralLetterDate, referralLetterDateAttrs] = defineField('referralLetterDate')
|
|
const [fromClinic, fromClinicAttrs] = defineField('fromClinic')
|
|
const [destinationClinic, destinationClinicAttrs] = defineField('destinationClinic')
|
|
const [attendingDoctor, attendingDoctorAttrs] = defineField('attendingDoctor')
|
|
const [initialDiagnosis, initialDiagnosisAttrs] = defineField('initialDiagnosis')
|
|
const [cob, cobAttrs] = defineField('cob')
|
|
const [cataract, cataractAttrs] = defineField('cataract')
|
|
const [clinicExcecutive, clinicExcecutiveAttrs] = defineField('clinicExcecutive')
|
|
const [procedureType, procedureTypeAttrs] = defineField('procedureType')
|
|
const [supportCode, supportCodeAttrs] = defineField('supportCode')
|
|
const [note, noteAttrs] = defineField('note')
|
|
const [classLevel, classLevelAttrs] = defineField('classLevel')
|
|
const [classLevelUpgrade, classLevelUpgradeAttrs] = defineField('classLevelUpgrade')
|
|
const [classPaySource, classPaySourceAttrs] = defineField('classPaySource')
|
|
const [responsiblePerson, responsiblePersonAttrs] = defineField('responsiblePerson')
|
|
const [accident, accidentAttrs] = defineField('trafficAccident')
|
|
const [purposeOfVisit, purposeOfVisitAttrs] = defineField('purposeOfVisit')
|
|
const [serviceAssessment, serviceAssessmentAttrs] = defineField('serviceAssessment')
|
|
const [lpNumber, lpNumberAttrs] = defineField('lpNumber')
|
|
const [accidentDate, accidentDateAttrs] = defineField('accidentDate')
|
|
const [accidentNote, accidentNoteAttrs] = defineField('accidentNote')
|
|
const [accidentProvince, accidentProvinceAttrs] = defineField('accidentProvince')
|
|
const [accidentCity, accidentCityAttrs] = defineField('accidentCity')
|
|
const [accidentDistrict, accidentDistrictAttrs] = defineField('accidentDistrict')
|
|
const [suplesi, suplesiAttrs] = defineField('suplesi')
|
|
const [suplesiNumber, suplesiNumberAttrs] = defineField('suplesiNumber')
|
|
const [subSpecialistId, subSpecialistIdAttrs] = defineField('subSpecialistId')
|
|
const titleLetterNumber = computed(() => (admissionType.value === '3' ? 'Surat Kontrol' : 'Surat Rujukan'))
|
|
const titleLetterDate = computed(() =>
|
|
admissionType.value === '3' ? 'Tanggal Surat Kontrol' : 'Tanggal Surat Rujukan',
|
|
)
|
|
const mode = props.mode !== undefined ? props.mode : 'add'
|
|
const attendingDoctorName = ref('')
|
|
const diagnosisName = ref('')
|
|
const isAccidentally = computed(() => accident.value === '1' || accident.value === '2')
|
|
const isProvinceSelected = computed(() => accidentProvince.value !== '')
|
|
const isCitySelected = computed(() => accidentCity.value !== '')
|
|
const isLoading = props.isLoading !== undefined ? props.isLoading : false
|
|
const isReadonly = props.isReadonly !== undefined ? props.isReadonly : false
|
|
const isService = ref(props.isService || false)
|
|
const isShowPatient = ref(props.isShowPatient || false)
|
|
const isShowSpecialist = ref(false)
|
|
const isDateReload = ref(false)
|
|
|
|
// Debounced search for bpjsNumber and nationalId
|
|
const debouncedCardNumber = refDebounced(cardNumber, 500)
|
|
const debouncedNationalId = refDebounced(nationalId, 500)
|
|
|
|
if (mode === 'add') {
|
|
// Set default sepDate to current date in YYYY-MM-DD format
|
|
const today = new Date()
|
|
const year = today.getFullYear()
|
|
const month = String(today.getMonth() + 1).padStart(2, '0')
|
|
const day = String(today.getDate()).padStart(2, '0')
|
|
sepDate.value = `${year}-${month}-${day}`
|
|
}
|
|
|
|
async function onFetchChildren(parentId: string): Promise<void> {
|
|
console.log('onFetchChildren', parentId)
|
|
}
|
|
|
|
const onBack = () => {
|
|
emit('event', 'back')
|
|
}
|
|
|
|
const onSaveNumber = () => {
|
|
emit('event', 'save-sep-number', { sepNumber: props?.objects?.sepNumber || '' })
|
|
}
|
|
|
|
// Submit handler
|
|
const onSubmit = handleSubmit((values) => {
|
|
emit('event', 'save-sep', values)
|
|
})
|
|
|
|
const onInitialized = (objects: any) => {
|
|
sepDate.value = objects?.registerDate || new Date().toISOString().substring(0, 10)
|
|
cardNumber.value = objects?.cardNumber || '-'
|
|
nationalId.value = objects?.nationalIdentity || '-'
|
|
medicalRecordNumber.value = objects?.medicalRecordNumber || '-'
|
|
patientName.value = objects?.patientName || '-'
|
|
phoneNumber.value = objects?.phoneNumber || '-'
|
|
if (objects?.sepType === 'internal') {
|
|
admissionType.value = '4'
|
|
}
|
|
if (objects?.sepType === 'external') {
|
|
admissionType.value = '1'
|
|
}
|
|
if (objects?.diagnosisName) {
|
|
diagnosisName.value = objects?.diagnosisName
|
|
}
|
|
// Patient data
|
|
if (objects?.serviceType) {
|
|
serviceType.value = objects?.serviceType
|
|
}
|
|
if (objects?.fromClinic) {
|
|
fromClinic.value = objects?.fromClinic
|
|
}
|
|
if (objects?.destinationClinic) {
|
|
destinationClinic.value = objects?.destinationClinic
|
|
}
|
|
// Doctor & Support data
|
|
if (objects?.attendingDoctor) {
|
|
attendingDoctor.value = objects?.attendingDoctor
|
|
}
|
|
if (objects?.attendingDoctorName) {
|
|
attendingDoctorName.value = objects?.attendingDoctorName
|
|
}
|
|
if (objects?.cob) {
|
|
cob.value = objects?.cob
|
|
}
|
|
if (objects?.cataract) {
|
|
cataract.value = objects?.cataract
|
|
}
|
|
if (objects?.clinicExcecutive) {
|
|
clinicExcecutive.value = objects?.clinicExcecutive
|
|
}
|
|
if (objects?.procedureType) {
|
|
procedureType.value = objects?.procedureType
|
|
}
|
|
if (objects?.supportCode) {
|
|
supportCode.value = objects?.supportCode
|
|
}
|
|
// Class & Payment data
|
|
if (objects?.classLevel) {
|
|
classLevel.value = objects?.classLevel
|
|
}
|
|
if (objects?.classLevelUpgrade) {
|
|
classLevelUpgrade.value = objects?.classLevelUpgrade
|
|
}
|
|
if (objects?.classPaySource) {
|
|
classPaySource.value = objects?.classPaySource
|
|
}
|
|
if (objects?.responsiblePerson) {
|
|
responsiblePerson.value = objects?.responsiblePerson
|
|
}
|
|
// Accident data
|
|
if (objects?.trafficAccident) {
|
|
accident.value = objects?.trafficAccident
|
|
}
|
|
if (objects?.lpNumber) {
|
|
lpNumber.value = objects?.lpNumber
|
|
}
|
|
if (objects?.accidentDate) {
|
|
accidentDate.value = objects?.accidentDate
|
|
}
|
|
if (objects?.accidentNote) {
|
|
accidentNote.value = objects?.accidentNote
|
|
}
|
|
if (objects?.accidentProvince) {
|
|
accidentProvince.value = objects?.accidentProvince
|
|
}
|
|
if (objects?.accidentCity) {
|
|
accidentCity.value = objects?.accidentCity
|
|
}
|
|
if (objects?.accidentDistrict) {
|
|
accidentDistrict.value = objects?.accidentDistrict
|
|
}
|
|
if (objects?.suplesi) {
|
|
suplesi.value = objects?.suplesi
|
|
}
|
|
if (objects?.suplesiNumber) {
|
|
suplesiNumber.value = objects?.suplesiNumber
|
|
}
|
|
// Visit purpose & Assessment
|
|
if (objects?.purposeOfVisit) {
|
|
purposeOfVisit.value = objects?.purposeOfVisit
|
|
}
|
|
if (objects?.serviceAssessment) {
|
|
serviceAssessment.value = objects?.serviceAssessment
|
|
}
|
|
// Note & Specialist
|
|
if (objects?.note) {
|
|
note.value = objects?.note
|
|
}
|
|
if (objects?.subSpecialistId) {
|
|
subSpecialistId.value = objects?.subSpecialistId
|
|
}
|
|
// Referral letter
|
|
if (objects?.referralLetterNumber) {
|
|
referralLetterNumber.value = objects?.referralLetterNumber
|
|
}
|
|
}
|
|
|
|
watch(props, (value) => {
|
|
const objects = value.objects || ({} as any)
|
|
if (Object.keys(objects).length > 0) {
|
|
onInitialized(objects)
|
|
isDateReload.value = true
|
|
setTimeout(() => {
|
|
if (objects?.sepDate) {
|
|
sepDate.value = objects?.sepDate
|
|
referralLetterDate.value = objects?.sepDate
|
|
}
|
|
if (objects?.letterDate) {
|
|
referralLetterDate.value = objects?.letterDate
|
|
}
|
|
isDateReload.value = false
|
|
}, 100)
|
|
}
|
|
})
|
|
|
|
// Watch debounced search values
|
|
watch(debouncedCardNumber, (newValue) => {
|
|
if (newValue && newValue !== '-' && newValue.length >= 3) {
|
|
emit('event', 'search-patient-by-identifier', { text: newValue, type: 'cardNumber' })
|
|
}
|
|
})
|
|
|
|
watch(debouncedNationalId, (newValue) => {
|
|
if (newValue && newValue !== '-' && newValue.length >= 3) {
|
|
emit('event', 'search-patient-by-identifier', { text: newValue, type: 'indentity' })
|
|
}
|
|
})
|
|
|
|
onMounted(() => {
|
|
if (!isService.value) {
|
|
serviceType.value = '2'
|
|
}
|
|
if (!admissionType.value) {
|
|
admissionType.value = '1'
|
|
}
|
|
})
|
|
</script>
|
|
|
|
<template>
|
|
<div class="mx-auto w-full">
|
|
<form
|
|
@submit.prevent="onSubmit"
|
|
class="grid gap-6 p-4"
|
|
>
|
|
<!-- Tanggal SEP & Jalur -->
|
|
<Block
|
|
labelSize="thin"
|
|
class="!pt-0"
|
|
:colCount="3"
|
|
:cellFlex="false"
|
|
>
|
|
<Cell>
|
|
<Label height="compact">
|
|
Tanggal SEP
|
|
<span class="ml-1 text-red-500">*</span>
|
|
</Label>
|
|
<Field :errMessage="errors.sepDate">
|
|
<DatepickerSingle
|
|
v-if="!isDateReload"
|
|
id="sepDate"
|
|
v-model="sepDate"
|
|
v-bind="sepDateAttrs"
|
|
:disabled="isLoading || isReadonly"
|
|
placeholder="Pilih tanggal sep"
|
|
/>
|
|
</Field>
|
|
</Cell>
|
|
|
|
<Cell v-if="isService">
|
|
<Label height="compact">Pelayanan</Label>
|
|
<Field :errMessage="errors.serviceType">
|
|
<Select
|
|
id="serviceType"
|
|
icon-name="i-lucide-chevron-down"
|
|
v-model="serviceType"
|
|
v-bind="serviceTypeAttrs"
|
|
:items="serviceTypes"
|
|
:disabled="isLoading || isReadonly"
|
|
placeholder="Pilih Pelayanan"
|
|
@change="emit('event', 'service-type', $event)"
|
|
/>
|
|
</Field>
|
|
</Cell>
|
|
|
|
<Cell>
|
|
<Label height="compact">Jalur</Label>
|
|
<Field :errMessage="errors.admissionType">
|
|
<Select
|
|
id="admissionType"
|
|
icon-name="i-lucide-chevron-down"
|
|
v-model="admissionType"
|
|
v-bind="admissionTypeAttrs"
|
|
:items="registerMethods"
|
|
:disabled="isLoading || isReadonly"
|
|
placeholder="Pilih jalur"
|
|
@change="emit('event', 'admission-type', $event)"
|
|
/>
|
|
</Field>
|
|
</Cell>
|
|
</Block>
|
|
|
|
<hr />
|
|
|
|
<!-- Data Pasien -->
|
|
<div class="flex items-center gap-2">
|
|
<h3 class="text-lg font-semibold">Data Pasien</h3>
|
|
<Button
|
|
v-if="isShowPatient"
|
|
variant="outline"
|
|
type="button"
|
|
class="h-[40px] rounded-md border-orange-400 text-orange-400 hover:bg-green-50"
|
|
@click="emit('event', 'search-patient')"
|
|
>
|
|
<Icon
|
|
name="i-lucide-search"
|
|
class="h-5 w-5"
|
|
/>
|
|
Cari Pasien
|
|
</Button>
|
|
</div>
|
|
|
|
<Block
|
|
labelSize="thin"
|
|
class="!pt-0"
|
|
:colCount="3"
|
|
:cellFlex="false"
|
|
>
|
|
<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"
|
|
/>
|
|
</Field>
|
|
</Cell>
|
|
|
|
<Cell>
|
|
<Label height="compact">
|
|
No. KTP
|
|
<span class="text-red-500">*</span>
|
|
</Label>
|
|
<Field :errMessage="errors.nationalId">
|
|
<Input
|
|
id="nationalId"
|
|
v-model="nationalId"
|
|
v-bind="nationalIdAttrs"
|
|
:disabled="isLoading || isReadonly"
|
|
/>
|
|
</Field>
|
|
</Cell>
|
|
|
|
<Cell>
|
|
<Label height="compact">
|
|
No. RM
|
|
<span class="text-red-500">*</span>
|
|
</Label>
|
|
<Field :errMessage="errors.medicalRecordNumber">
|
|
<Input
|
|
id="medicalRecordNumber"
|
|
v-model="medicalRecordNumber"
|
|
v-bind="medicalRecordNumberAttrs"
|
|
:disabled="true"
|
|
/>
|
|
</Field>
|
|
</Cell>
|
|
|
|
<Cell>
|
|
<Label height="compact">
|
|
Nama Pasien
|
|
<span class="text-red-500">*</span>
|
|
</Label>
|
|
<Field :errMessage="errors.patientName">
|
|
<Input
|
|
id="patientName"
|
|
v-model="patientName"
|
|
v-bind="patientNameAttrs"
|
|
:disabled="true"
|
|
/>
|
|
</Field>
|
|
</Cell>
|
|
|
|
<Cell>
|
|
<Label height="compact">
|
|
No. Telepon
|
|
<span class="text-red-500">*</span>
|
|
</Label>
|
|
<Field :errMessage="errors.phoneNumber">
|
|
<Input
|
|
id="phoneNumber"
|
|
v-model="phoneNumber"
|
|
v-bind="phoneNumberAttrs"
|
|
:disabled="true"
|
|
/>
|
|
</Field>
|
|
</Cell>
|
|
</Block>
|
|
|
|
<hr />
|
|
|
|
<!-- Data SEP -->
|
|
<h3 class="text-lg font-semibold">Data SEP</h3>
|
|
<Block
|
|
labelSize="thin"
|
|
class="!pt-0"
|
|
:colCount="3"
|
|
:cellFlex="false"
|
|
>
|
|
<Cell>
|
|
<Label height="compact">
|
|
{{ titleLetterNumber }}
|
|
<span class="text-red-500">*</span>
|
|
</Label>
|
|
<Field :errMessage="errors.referralLetterNumber">
|
|
<div class="flex gap-2">
|
|
<Input
|
|
id="referralLetterNumber"
|
|
class="flex-1"
|
|
v-model="referralLetterNumber"
|
|
v-bind="referralLetterNumberAttrs"
|
|
:disabled="isLoading || isReadonly"
|
|
@change="
|
|
emit('event', 'search-letter', { admissionType, serviceType, search: referralLetterNumber || '' })
|
|
"
|
|
/>
|
|
<Button
|
|
v-if="!isReadonly"
|
|
variant="outline"
|
|
type="button"
|
|
class="h-[40px] rounded-md border-orange-400 text-orange-400 hover:bg-green-50"
|
|
@click="
|
|
emit('event', 'open-letter', { admissionType, serviceType, search: referralLetterNumber || '' })
|
|
"
|
|
>
|
|
<Icon
|
|
name="i-lucide-search"
|
|
class="h-5 w-5"
|
|
/>
|
|
Cari Data
|
|
</Button>
|
|
</div>
|
|
</Field>
|
|
</Cell>
|
|
|
|
<Cell>
|
|
<Label height="compact">
|
|
{{ titleLetterDate }}
|
|
<span class="text-red-500">*</span>
|
|
</Label>
|
|
<Field :errMessage="errors.referralLetterDate">
|
|
<DatepickerSingle
|
|
v-if="!isDateReload"
|
|
id="referralLetterDate"
|
|
v-model="referralLetterDate"
|
|
v-bind="referralLetterDateAttrs"
|
|
:disabled="isLoading || isReadonly"
|
|
placeholder="Pilih tanggal surat"
|
|
/>
|
|
</Field>
|
|
</Cell>
|
|
|
|
<Cell>
|
|
<Label height="compact">
|
|
Klinik Eksekutif
|
|
<span class="text-red-500">*</span>
|
|
</Label>
|
|
<Field :errMessage="errors.clinicExcecutive">
|
|
<RadioGroup
|
|
v-model="clinicExcecutive"
|
|
v-bind="clinicExcecutiveAttrs"
|
|
class="flex items-center gap-2"
|
|
:disabled="isLoading || isReadonly"
|
|
>
|
|
<div class="flex items-center space-x-2">
|
|
<RadioGroupItem
|
|
value="yes"
|
|
id="clinicExcecutive-yes"
|
|
/>
|
|
<Label for="clinicExcecutive-yes">Ya</Label>
|
|
</div>
|
|
<div class="flex items-center space-x-2">
|
|
<RadioGroupItem
|
|
value="no"
|
|
id="clinicExcecutive-no"
|
|
/>
|
|
<Label for="clinicExcecutive-no">Tidak</Label>
|
|
</div>
|
|
</RadioGroup>
|
|
</Field>
|
|
</Cell>
|
|
|
|
<Cell v-if="serviceType === '1'">
|
|
<Label height="compact">
|
|
Faskes Asal
|
|
<span class="text-red-500">*</span>
|
|
</Label>
|
|
<Field :errMessage="errors.fromClinic">
|
|
<Combobox
|
|
id="fromClinic"
|
|
v-model="fromClinic"
|
|
v-bind="fromClinicAttrs"
|
|
:items="facilitiesFrom"
|
|
:is-disabled="isLoading || isReadonly"
|
|
placeholder="Pilih Asal"
|
|
search-placeholder="Cari Asal"
|
|
empty-message="Item tidak ditemukan"
|
|
@update:searchText="emit('fetch', { menu: 'clinic-from', value: $event })"
|
|
/>
|
|
</Field>
|
|
</Cell>
|
|
|
|
<Cell v-if="isShowPatient">
|
|
<Label height="compact">
|
|
Klinik Tujuan
|
|
<span class="text-red-500">*</span>
|
|
</Label>
|
|
<Field :errMessage="errors.destinationClinic">
|
|
<Combobox
|
|
id="destinationClinic"
|
|
v-model="destinationClinic"
|
|
v-bind="destinationClinicAttrs"
|
|
:items="facilitiesTo"
|
|
:is-disabled="isLoading || isReadonly"
|
|
placeholder="Pilih Klinik"
|
|
search-placeholder="Cari Klinik"
|
|
empty-message="Item tidak ditemukan"
|
|
@update:searchText="emit('fetch', { menu: 'clinic-to', value: $event })"
|
|
/>
|
|
</Field>
|
|
</Cell>
|
|
|
|
<Cell v-if="!isReadonly && isShowSpecialist">
|
|
<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>
|
|
|
|
<Cell>
|
|
<Label height="compact">
|
|
DPJP
|
|
<span class="text-red-500">*</span>
|
|
</Label>
|
|
<Field :errMessage="errors.attendingDoctor">
|
|
<Combobox
|
|
v-if="!isReadonly"
|
|
id="attendingDoctor"
|
|
v-model="attendingDoctor"
|
|
v-bind="attendingDoctorAttrs"
|
|
:items="doctors"
|
|
:is-disabled="isLoading || isReadonly"
|
|
placeholder="Pilih DPJP"
|
|
search-placeholder="Cari DPJP"
|
|
empty-message="Item tidak ditemukan"
|
|
@update:searchText="emit('fetch', { menu: 'doctor', value: $event })"
|
|
/>
|
|
<Input
|
|
v-else
|
|
v-model="attendingDoctorName"
|
|
v-bind="attendingDoctorAttrs"
|
|
:disabled="isLoading || isReadonly"
|
|
/>
|
|
</Field>
|
|
</Cell>
|
|
|
|
<Cell>
|
|
<Label height="compact">
|
|
Diagnosa Awal
|
|
<span class="text-red-500">*</span>
|
|
</Label>
|
|
<Field :errMessage="errors.initialDiagnosis">
|
|
<Combobox
|
|
v-if="!isReadonly"
|
|
id="initialDiagnosis"
|
|
v-model="initialDiagnosis"
|
|
v-bind="initialDiagnosisAttrs"
|
|
:items="diagnoses"
|
|
:is-disabled="isLoading || isReadonly"
|
|
placeholder="Pilih Diagnosa Awal"
|
|
search-placeholder="Cari Diagnosa Awal"
|
|
empty-message="Item tidak ditemukan"
|
|
@update:searchText="emit('fetch', { menu: 'diagnosis', value: $event })"
|
|
/>
|
|
<Input
|
|
v-else
|
|
v-model="diagnosisName"
|
|
v-bind="initialDiagnosisAttrs"
|
|
:disabled="isLoading || isReadonly"
|
|
/>
|
|
</Field>
|
|
</Cell>
|
|
</Block>
|
|
|
|
<Block
|
|
labelSize="thin"
|
|
class="!pt-0"
|
|
:colCount="1"
|
|
:cellFlex="false"
|
|
>
|
|
<Cell>
|
|
<Label height="dynamic">Catatan</Label>
|
|
<Field>
|
|
<Textarea
|
|
id="note"
|
|
v-model="note"
|
|
v-bind="noteAttrs"
|
|
class="h-[200px] w-full border-gray-400 bg-white"
|
|
placeholder="Masukkan catatan opsional"
|
|
:disabled="isLoading || isReadonly"
|
|
/>
|
|
</Field>
|
|
</Cell>
|
|
</Block>
|
|
|
|
<Block
|
|
v-if="serviceType === '1'"
|
|
labelSize="thin"
|
|
class="!pt-0"
|
|
:colCount="3"
|
|
:cellFlex="false"
|
|
>
|
|
<Cell>
|
|
<Label height="dynamic">
|
|
Kelas Rawat
|
|
<span class="text-red-500">*</span>
|
|
</Label>
|
|
<Field :errMessage="errors.classLevel">
|
|
<Select
|
|
id="classLevel"
|
|
v-model="classLevel"
|
|
v-bind="classLevelAttrs"
|
|
:items="classLevels"
|
|
:disabled="isLoading || isReadonly"
|
|
placeholder="Pilih Kelas Rawat"
|
|
/>
|
|
</Field>
|
|
</Cell>
|
|
|
|
<Cell>
|
|
<Label height="dynamic">
|
|
Kelas Rawat Naik
|
|
<span class="text-red-500">*</span>
|
|
</Label>
|
|
<Field :errMessage="errors.classLevelUpgrade">
|
|
<Select
|
|
id="classLevelUpgrade"
|
|
v-model="classLevelUpgrade"
|
|
v-bind="classLevelUpgradeAttrs"
|
|
:items="classLevelUpgrades"
|
|
:disabled="isLoading || isReadonly"
|
|
placeholder="Pilih Kelas Rawat Naik"
|
|
/>
|
|
</Field>
|
|
</Cell>
|
|
|
|
<Cell>
|
|
<Label height="dynamic">
|
|
Pembiayaan
|
|
<span class="text-red-500">*</span>
|
|
</Label>
|
|
<Field :errMessage="errors.classPaySource">
|
|
<Select
|
|
id="classPaySource"
|
|
v-model="classPaySource"
|
|
v-bind="classPaySourceAttrs"
|
|
:items="classPaySources"
|
|
:disabled="isLoading || isReadonly"
|
|
placeholder="Pilih Pembiayaan"
|
|
/>
|
|
</Field>
|
|
</Cell>
|
|
</Block>
|
|
|
|
<Block
|
|
v-if="serviceType === '1' && classLevelUpgrade !== ''"
|
|
labelSize="thin"
|
|
class="!pt-0"
|
|
:colCount="1"
|
|
:cellFlex="false"
|
|
>
|
|
<Cell>
|
|
<Label height="dynamic">
|
|
Penanggung Jawab
|
|
<span class="text-red-500">*</span>
|
|
</Label>
|
|
<Field :errMessage="errors.responsiblePerson">
|
|
<Input
|
|
id="responsiblePerson"
|
|
v-model="responsiblePerson"
|
|
v-bind="responsiblePersonAttrs"
|
|
:disabled="isLoading || isReadonly"
|
|
placeholder="Masukkan penanggung jawab"
|
|
/>
|
|
</Field>
|
|
</Cell>
|
|
</Block>
|
|
|
|
<Block
|
|
labelSize="thin"
|
|
class="!pt-0"
|
|
:colCount="3"
|
|
:cellFlex="false"
|
|
>
|
|
<Cell>
|
|
<Label height="compact">
|
|
COB
|
|
<span class="text-red-500">*</span>
|
|
</Label>
|
|
<Field :errMessage="errors.cob">
|
|
<RadioGroup
|
|
v-model="cob"
|
|
v-bind="cobAttrs"
|
|
class="flex items-center gap-2"
|
|
:disabled="isLoading || isReadonly"
|
|
>
|
|
<div class="flex items-center space-x-2">
|
|
<RadioGroupItem
|
|
value="yes"
|
|
id="cob-yes"
|
|
/>
|
|
<Label for="cob-yes">Ya</Label>
|
|
</div>
|
|
<div class="flex items-center space-x-2">
|
|
<RadioGroupItem
|
|
value="no"
|
|
id="cob-no"
|
|
/>
|
|
<Label for="cob-no">Tidak</Label>
|
|
</div>
|
|
</RadioGroup>
|
|
</Field>
|
|
</Cell>
|
|
|
|
<Cell>
|
|
<Label height="compact">
|
|
Katarak
|
|
<span class="text-red-500">*</span>
|
|
</Label>
|
|
<Field :errMessage="errors.cataract">
|
|
<RadioGroup
|
|
v-model="cataract"
|
|
v-bind="cataractAttrs"
|
|
class="flex items-center gap-2"
|
|
:disabled="isLoading || isReadonly"
|
|
>
|
|
<div class="flex items-center space-x-2">
|
|
<RadioGroupItem
|
|
value="yes"
|
|
id="cataract-yes"
|
|
/>
|
|
<Label for="cataract-yes">Ya</Label>
|
|
</div>
|
|
<div class="flex items-center space-x-2">
|
|
<RadioGroupItem
|
|
value="no"
|
|
id="cataract-no"
|
|
/>
|
|
<Label for="cataract-no">Tidak</Label>
|
|
</div>
|
|
</RadioGroup>
|
|
</Field>
|
|
</Cell>
|
|
</Block>
|
|
|
|
<Block
|
|
labelSize="thin"
|
|
class="!pt-0"
|
|
:colCount="3"
|
|
:cellFlex="false"
|
|
>
|
|
<Cell>
|
|
<Label height="compact">
|
|
Status Kecelakaan
|
|
<span class="text-red-500">*</span>
|
|
</Label>
|
|
<Field :errMessage="errors.trafficAccident">
|
|
<Select
|
|
id="accident"
|
|
icon-name="i-lucide-chevron-down"
|
|
v-model="accident"
|
|
v-bind="accidentAttrs"
|
|
:items="accidents"
|
|
:disabled="isLoading || isReadonly"
|
|
placeholder="Pilih Status Kecelakaan"
|
|
/>
|
|
</Field>
|
|
</Cell>
|
|
|
|
<Cell v-if="isAccidentally">
|
|
<Label height="compact">
|
|
No LP
|
|
<span class="text-red-500">*</span>
|
|
</Label>
|
|
<Field :errMessage="errors.lpNumber">
|
|
<Input
|
|
id="lpNumber"
|
|
v-model="lpNumber"
|
|
v-bind="lpNumberAttrs"
|
|
:disabled="isLoading || isReadonly"
|
|
/>
|
|
</Field>
|
|
</Cell>
|
|
|
|
<Cell v-if="isAccidentally">
|
|
<Label height="compact">
|
|
Tanggal Kejadian
|
|
<span class="text-red-500">*</span>
|
|
</Label>
|
|
<Field :errMessage="errors.accidentDate">
|
|
<DatepickerSingle
|
|
id="accidentDate"
|
|
v-model="accidentDate"
|
|
v-bind="accidentDateAttrs"
|
|
:disabled="isLoading || isReadonly"
|
|
placeholder="Pilih tanggal kejadian"
|
|
/>
|
|
</Field>
|
|
</Cell>
|
|
|
|
<Cell v-if="isAccidentally">
|
|
<Label height="compact">
|
|
Keterangan
|
|
<span class="text-red-500">*</span>
|
|
</Label>
|
|
<Field :errMessage="errors.accidentNote">
|
|
<Input
|
|
id="accidentNote"
|
|
v-model="accidentNote"
|
|
v-bind="accidentNoteAttrs"
|
|
:disabled="isLoading || isReadonly"
|
|
/>
|
|
</Field>
|
|
</Cell>
|
|
|
|
<Cell v-if="isAccidentally">
|
|
<Label height="compact">
|
|
Provinsi
|
|
<span class="text-red-500">*</span>
|
|
</Label>
|
|
<Field :errMessage="errors.accidentProvince">
|
|
<Combobox
|
|
id="accidentProvince"
|
|
v-model="accidentProvince"
|
|
v-bind="accidentProvinceAttrs"
|
|
:items="provinces"
|
|
:is-disabled="isLoading || isReadonly"
|
|
placeholder="Pilih Provinsi"
|
|
search-placeholder="Cari Provinsi"
|
|
empty-message="Item tidak ditemukan"
|
|
@update:modelValue="emit('fetch', { menu: 'province', value: $event })"
|
|
/>
|
|
</Field>
|
|
</Cell>
|
|
|
|
<Cell v-if="isAccidentally">
|
|
<Label height="compact">
|
|
Kota
|
|
<span class="text-red-500">*</span>
|
|
</Label>
|
|
<Field :errMessage="errors.accidentCity">
|
|
<Combobox
|
|
id="accidentCity"
|
|
v-model="accidentCity"
|
|
v-bind="accidentCityAttrs"
|
|
:items="cities"
|
|
:is-disabled="isLoading || isReadonly || !isProvinceSelected"
|
|
placeholder="Pilih Kota"
|
|
search-placeholder="Cari Kota"
|
|
empty-message="Item tidak ditemukan"
|
|
@update:modelValue="emit('fetch', { menu: 'city', value: $event })"
|
|
/>
|
|
</Field>
|
|
</Cell>
|
|
|
|
<Cell v-if="isAccidentally">
|
|
<Label height="compact">
|
|
Kecamatan
|
|
<span class="text-red-500">*</span>
|
|
</Label>
|
|
<Field :errMessage="errors.accidentDistrict">
|
|
<Combobox
|
|
id="accidentDistrict"
|
|
v-model="accidentDistrict"
|
|
v-bind="accidentDistrictAttrs"
|
|
:items="districts"
|
|
:is-disabled="isLoading || isReadonly || !isProvinceSelected || !isCitySelected"
|
|
placeholder="Pilih Kecamatan"
|
|
search-placeholder="Cari Kecamatan"
|
|
empty-message="Item tidak ditemukan"
|
|
@update:modelValue="emit('fetch', { menu: 'district', value: $event })"
|
|
/>
|
|
</Field>
|
|
</Cell>
|
|
|
|
<Cell v-if="isAccidentally">
|
|
<Label height="compact">
|
|
Suplesi
|
|
<span class="text-red-500">*</span>
|
|
</Label>
|
|
<Field :errMessage="errors.suplesi">
|
|
<RadioGroup
|
|
v-model="suplesi"
|
|
v-bind="suplesiAttrs"
|
|
class="flex items-center gap-2"
|
|
>
|
|
<div class="flex items-center space-x-2">
|
|
<RadioGroupItem
|
|
value="yes"
|
|
id="suplesi-yes"
|
|
/>
|
|
<Label for="suplesi-yes">Ya</Label>
|
|
</div>
|
|
<div class="flex items-center space-x-2">
|
|
<RadioGroupItem
|
|
value="no"
|
|
id="suplesi-no"
|
|
/>
|
|
<Label for="suplesi-no">Tidak</Label>
|
|
</div>
|
|
</RadioGroup>
|
|
</Field>
|
|
</Cell>
|
|
|
|
<Cell v-if="isAccidentally && suplesi === 'yes'">
|
|
<Label height="compact">
|
|
No. SEP Suplesi
|
|
<span class="text-red-500">*</span>
|
|
</Label>
|
|
<Field :errMessage="errors.suplesiNumber">
|
|
<Input
|
|
id="lpNumber"
|
|
v-model="suplesiNumber"
|
|
v-bind="suplesiNumberAttrs"
|
|
:disabled="isLoading || isReadonly"
|
|
/>
|
|
</Field>
|
|
</Cell>
|
|
</Block>
|
|
|
|
<Block
|
|
labelSize="thin"
|
|
class="!pt-0"
|
|
:colCount="3"
|
|
:cellFlex="false"
|
|
>
|
|
<Cell>
|
|
<Label height="compact">
|
|
Tujuan Kunjungan
|
|
<span class="text-red-500">*</span>
|
|
</Label>
|
|
<Field :errMessage="errors.purposeOfVisit">
|
|
<Select
|
|
id="purposeOfVisit"
|
|
icon-name="i-lucide-chevron-down"
|
|
v-model="purposeOfVisit"
|
|
v-bind="purposeOfVisitAttrs"
|
|
:items="purposes"
|
|
:disabled="isLoading || isReadonly"
|
|
placeholder="Pilih Tujuan Kunjungan"
|
|
/>
|
|
</Field>
|
|
</Cell>
|
|
|
|
<Cell v-if="purposeOfVisit === '1'">
|
|
<Label height="compact">
|
|
Jenis Prosedur
|
|
<span class="text-red-500">*</span>
|
|
</Label>
|
|
<Field :errMessage="errors.procedureType">
|
|
<Select
|
|
id="procedureType"
|
|
icon-name="i-lucide-chevron-down"
|
|
v-model="procedureType"
|
|
v-bind="procedureTypeAttrs"
|
|
:items="procedures"
|
|
:disabled="isLoading || isReadonly"
|
|
placeholder="Pilih Jenis Prosedur"
|
|
/>
|
|
</Field>
|
|
</Cell>
|
|
|
|
<Cell v-if="purposeOfVisit === '2'">
|
|
<Label height="compact">
|
|
Assemen Pelayanan
|
|
<span class="text-red-500">*</span>
|
|
</Label>
|
|
<Field :errMessage="errors.serviceAssessment">
|
|
<Select
|
|
id="serviceAssessment"
|
|
icon-name="i-lucide-chevron-down"
|
|
v-model="serviceAssessment"
|
|
v-bind="serviceAssessmentAttrs"
|
|
:items="assessments"
|
|
:disabled="isLoading || isReadonly"
|
|
placeholder="Pilih Assemen Pelayanan"
|
|
/>
|
|
</Field>
|
|
</Cell>
|
|
|
|
<Cell v-if="purposeOfVisit === '1'">
|
|
<Label height="compact">
|
|
Kode Penunjang
|
|
<span class="text-red-500">*</span>
|
|
</Label>
|
|
<Field :errMessage="errors.supportCode">
|
|
<Select
|
|
id="supportCode"
|
|
icon-name="i-lucide-chevron-down"
|
|
v-model="supportCode"
|
|
v-bind="supportCodeAttrs"
|
|
:items="supportCodes"
|
|
:disabled="isLoading || isReadonly"
|
|
placeholder="Pilih Kode Penunjang"
|
|
/>
|
|
</Field>
|
|
</Cell>
|
|
</Block>
|
|
|
|
<!-- {{ JSON.stringify(errors, null, 2) }} -->
|
|
|
|
<!-- Actions -->
|
|
<div class="mt-6 flex justify-end gap-2">
|
|
<Button
|
|
v-if="props.mode === 'detail'"
|
|
variant="ghost"
|
|
type="button"
|
|
class="h-[40px] min-w-[120px] text-orange-400 hover:bg-green-50"
|
|
@click="emit('event', 'history-sep')"
|
|
>
|
|
<Icon
|
|
name="i-lucide-history"
|
|
class="h-5 w-5"
|
|
/>
|
|
Riwayat SEP
|
|
</Button>
|
|
<Button
|
|
v-if="props.mode === 'detail'"
|
|
variant="outline"
|
|
type="button"
|
|
class="h-[40px] min-w-[120px] rounded-md border-orange-400 text-orange-400 hover:bg-green-50 hover:text-orange-400"
|
|
>
|
|
<Icon
|
|
name="i-lucide-eye"
|
|
class="h-5 w-5"
|
|
/>
|
|
Preview
|
|
</Button>
|
|
<Button
|
|
v-if="props.mode === 'add'"
|
|
type="button"
|
|
class="h-[40px] min-w-[120px] text-white"
|
|
:disabled="isLoading"
|
|
@click="onSubmit"
|
|
>
|
|
<Icon
|
|
name="i-lucide-save"
|
|
class="h-5 w-5"
|
|
/>
|
|
Simpan
|
|
</Button>
|
|
<Button
|
|
v-if="props.mode === 'detail'"
|
|
type="button"
|
|
class="h-[40px] min-w-[120px] text-white"
|
|
:disabled="isLoading"
|
|
@click="onBack"
|
|
>
|
|
<Icon
|
|
name="i-lucide-chevron-left"
|
|
class="h-5 w-5"
|
|
/>
|
|
Kembali
|
|
</Button>
|
|
<Button
|
|
v-if="props.mode === 'link'"
|
|
type="button"
|
|
class="h-[40px] min-w-[120px] text-white"
|
|
:disabled="isLoading"
|
|
@click="onSaveNumber"
|
|
>
|
|
<Icon
|
|
name="i-lucide-save"
|
|
class="h-5 w-5"
|
|
/>
|
|
Terapkan
|
|
</Button>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
</template>
|