wip: encounter edit
This commit is contained in:
@@ -0,0 +1,699 @@
|
||||
<script setup lang="ts">
|
||||
// Components
|
||||
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 * as CB from '~/components/pub/my-ui/combobox'
|
||||
|
||||
import DatepickerSingle from '~/components/pub/my-ui/datepicker/datepicker-single.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'
|
||||
|
||||
// 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<{
|
||||
mode?: string
|
||||
isLoading?: boolean
|
||||
isReadonly?: boolean
|
||||
isSepValid?: boolean
|
||||
isMemberValid?: boolean
|
||||
isCheckingSep?: boolean
|
||||
doctorItems?: CB.Item[]
|
||||
selectedDoctor: Doctor
|
||||
// subSpecialist?: any[]
|
||||
// specialists?: TreeItem[]
|
||||
payments?: any[]
|
||||
participantGroups?: any[]
|
||||
seps: any[]
|
||||
patient?: PatientEntity | null | undefined
|
||||
objects?: any
|
||||
}>()
|
||||
|
||||
// Model
|
||||
const model = defineModel<Encounter>()
|
||||
model.value = genEncounter()
|
||||
|
||||
// Common preparation
|
||||
const defaultCBItems = [{ label: 'Pilih', value: '' }]
|
||||
const paymentMethodItems = ref<any>({})
|
||||
|
||||
// Emit preparation
|
||||
const emit = defineEmits<{
|
||||
(e: 'onSelectDoctor', code: string): void
|
||||
(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 [doctorCode, doctorCodeAttrs] = defineField('doctor_code')
|
||||
const [unitCode, unitCodeAttrs] = defineField('unit_code')
|
||||
const [registerDate, registerDateAttrs] = defineField('registerDate')
|
||||
const [paymentMethodCode, paymentMethodCodeAttrs] = defineField('paymentMethod_code')
|
||||
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 [sepFile, sepFileAttrs] = defineField('sepFile')
|
||||
const [sippFile, sippFileAttrs] = defineField('sippFile')
|
||||
const patientId = ref('')
|
||||
const sepReference = ref('')
|
||||
const sepControlDate = ref('')
|
||||
const sepTrafficStatus = ref('')
|
||||
const diagnosis = ref('')
|
||||
const noteReference = ref('Hanya diperlukan jika pembayaran jenis JKN')
|
||||
const noteFile = ref('Gunakan file [.pdf, .jpg, .png] dengan ukuran maksimal 1MB')
|
||||
|
||||
const isLoading = props.isLoading !== undefined ? props.isLoading : false
|
||||
const isReadonly = props.isReadonly !== undefined ? props.isReadonly : false
|
||||
const mode = props.mode !== undefined ? props.mode : 'add'
|
||||
// SEP validation state from props
|
||||
const isSepValid = computed(() => props.isSepValid || false)
|
||||
const isCheckingSep = computed(() => props.isCheckingSep || false)
|
||||
const isInsurancePayment = computed(() => ['insurance', 'jkn'].includes(paymentMethodCode.value))
|
||||
const isDateLoading = ref(false)
|
||||
const debouncedSepNumber = refDebounced(sepNumber, 500)
|
||||
const debouncedCardNumber = refDebounced(cardNumber, 500)
|
||||
const sepFileReview = ref<any>(null)
|
||||
const sippFileReview = ref<any>(null)
|
||||
const unitFullName = ref('') // Unit, specialist, subspecialist
|
||||
const formRef = ref<HTMLFormElement | null>(null) // Expose submit method for parent component
|
||||
|
||||
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')
|
||||
registerDate.value = `${year}-${month}-${day}`
|
||||
}
|
||||
|
||||
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 || ''
|
||||
},
|
||||
)
|
||||
|
||||
// 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 || ''
|
||||
doctorCode.value = objects?.doctorCode || ''
|
||||
paymentMethodCode.value = objects?.paymentMethodCode || ''
|
||||
patientCategory.value = objects?.patientCategory || ''
|
||||
cardNumber.value = objects?.cardNumber || ''
|
||||
sepType.value = objects?.sepType || ''
|
||||
sepNumber.value = objects?.sepNumber || ''
|
||||
sepFileReview.value = objects?.sepFileReview || ''
|
||||
sippFileReview.value = objects?.sippFileReview || ''
|
||||
isDateLoading.value = true
|
||||
setTimeout(() => {
|
||||
registerDate.value = objects?.registerDate || ''
|
||||
isDateLoading.value = false
|
||||
}, 100)
|
||||
}
|
||||
},
|
||||
{ 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 },
|
||||
)
|
||||
|
||||
watch(
|
||||
() => props.isSepValid,
|
||||
(value) => {
|
||||
if (!value) return
|
||||
const objects = props.objects
|
||||
if (objects && Object.keys(objects).length > 0) {
|
||||
sepReference.value = objects?.sepReference || ''
|
||||
sepControlDate.value = objects?.sepControlDate || ''
|
||||
sepTrafficStatus.value = objects?.sepTrafficStatus || ''
|
||||
diagnosis.value = objects?.diagnosis || ''
|
||||
}
|
||||
},
|
||||
)
|
||||
|
||||
watch(debouncedSepNumber, (newValue) => {
|
||||
emit('event', 'sep-number-changed', newValue)
|
||||
})
|
||||
|
||||
watch(debouncedCardNumber, (newValue) => {
|
||||
emit('event', 'member-changed', newValue)
|
||||
})
|
||||
|
||||
function onAddSep() {
|
||||
const formValues = {
|
||||
patientId: patientId.value || '',
|
||||
doctorCode: doctorCode.value,
|
||||
registerDate: registerDate.value,
|
||||
cardNumber: cardNumber.value,
|
||||
paymentMethodCode: paymentMethodCode.value,
|
||||
sepFile: sepFile.value,
|
||||
sippFile: sippFile.value,
|
||||
sepType: sepType.value,
|
||||
}
|
||||
emit('event', 'add-sep', formValues)
|
||||
}
|
||||
|
||||
function onSearchSep() {
|
||||
emit('event', 'search-sep', { cardNumber: cardNumber.value })
|
||||
}
|
||||
|
||||
// Submit handler
|
||||
const onSubmit = handleSubmit((values) => {
|
||||
let payload: any = values
|
||||
if (props.mode === 'edit') {
|
||||
payload = {
|
||||
...payload,
|
||||
sepFileReview: sepFileReview.value,
|
||||
sippFileReview: sippFileReview.value,
|
||||
}
|
||||
}
|
||||
emit('event', 'save', payload)
|
||||
})
|
||||
|
||||
function openFile(path: string) {
|
||||
window.open(path, '_blank')
|
||||
}
|
||||
|
||||
function submitForm() {
|
||||
// Trigger form submit using native form submit
|
||||
// This will trigger validation and onSubmit handler
|
||||
if (formRef.value) {
|
||||
formRef.value.requestSubmit()
|
||||
} else {
|
||||
// Fallback: directly call onSubmit handler
|
||||
// Create a mock event object
|
||||
const mockEvent = {
|
||||
preventDefault: () => {},
|
||||
target: formRef.value || {},
|
||||
} as SubmitEvent
|
||||
|
||||
// Call onSubmit directly
|
||||
onSubmit(mockEvent)
|
||||
}
|
||||
}
|
||||
|
||||
defineExpose({
|
||||
submitForm,
|
||||
})
|
||||
|
||||
onMounted(() => {
|
||||
const isPaymentMethodVclaim = true
|
||||
paymentMethodItems.value = isPaymentMethodVclaim ? props.payments : CB.recStrToItem(paymentMethodCodes)
|
||||
})
|
||||
</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>
|
||||
|
||||
<DE.Block
|
||||
labelSize="thin"
|
||||
class="!pt-0"
|
||||
:colCount="3"
|
||||
:cellFlex="false"
|
||||
>
|
||||
<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"
|
||||
/>
|
||||
</DE.Field>
|
||||
</DE.Cell>
|
||||
|
||||
<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"
|
||||
/>
|
||||
</DE.Field>
|
||||
</DE.Cell>
|
||||
|
||||
<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"
|
||||
/>
|
||||
</DE.Field>
|
||||
</DE.Cell>
|
||||
</DE.Block>
|
||||
|
||||
<hr />
|
||||
|
||||
<!-- Data Kunjungan -->
|
||||
<h3 class="text-lg font-semibold">Data Kunjungan</h3>
|
||||
|
||||
<DE.Block
|
||||
labelSize="thin"
|
||||
class="!pt-0"
|
||||
:colCount="3"
|
||||
:cellFlex="false"
|
||||
>
|
||||
<DE.Cell>
|
||||
<DE.Label height="compact">
|
||||
Dokter
|
||||
<span class="text-red-500">*</span>
|
||||
</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: any) => emit('onSelectDoctor', value)"
|
||||
/>
|
||||
</DE.Field>
|
||||
</DE.Cell>
|
||||
|
||||
<DE.Cell>
|
||||
<DE.Label height="compact">
|
||||
Spesialis / Subspesialis
|
||||
<span class="text-red-500">*</span>
|
||||
</DE.Label>
|
||||
<DE.Field :errMessage="errors.unit_code">
|
||||
<Input
|
||||
:value="unitFullName"
|
||||
:disabled="true"
|
||||
/>
|
||||
</DE.Field>
|
||||
</DE.Cell>
|
||||
|
||||
<DE.Cell>
|
||||
<DE.Label height="compact">
|
||||
Tanggal Daftar
|
||||
<span class="text-red-500">*</span>
|
||||
</DE.Label>
|
||||
<DE.Field :errMessage="errors.registerDate">
|
||||
<DatepickerSingle
|
||||
v-if="!isDateLoading"
|
||||
id="registerDate"
|
||||
v-model="registerDate"
|
||||
v-bind="registerDateAttrs"
|
||||
placeholder="Pilih tanggal"
|
||||
/>
|
||||
</DE.Field>
|
||||
</DE.Cell>
|
||||
</DE.Block>
|
||||
|
||||
<DE.Block
|
||||
labelSize="thin"
|
||||
class="!pt-0"
|
||||
:colCount="3"
|
||||
:cellFlex="false"
|
||||
>
|
||||
<DE.Cell>
|
||||
<DE.Label height="compact">
|
||||
Jenis Pembayaran
|
||||
<span class="text-red-500">*</span>
|
||||
</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"
|
||||
/>
|
||||
</DE.Field>
|
||||
</DE.Cell>
|
||||
</DE.Block>
|
||||
|
||||
<!-- BPJS Fields (conditional) -->
|
||||
<template v-if="isInsurancePayment">
|
||||
<DE.Block
|
||||
labelSize="thin"
|
||||
class="!pt-0"
|
||||
:colCount="3"
|
||||
:cellFlex="false"
|
||||
>
|
||||
<DE.Cell>
|
||||
<DE.Label height="compact">
|
||||
Kelompok Peserta
|
||||
<span class="text-red-500">*</span>
|
||||
</DE.Label>
|
||||
<DE.Field :errMessage="errors.patientCategory">
|
||||
<Select
|
||||
id="patientCategory"
|
||||
v-model="patientCategory"
|
||||
v-bind="patientCategoryAttrs"
|
||||
:items="participantGroups || []"
|
||||
:disabled="isLoading || isReadonly"
|
||||
placeholder="Pilih Kelompok Peserta"
|
||||
/>
|
||||
</DE.Field>
|
||||
<span class="text-sm text-gray-500">
|
||||
{{ noteReference }}
|
||||
</span>
|
||||
</DE.Cell>
|
||||
|
||||
<DE.Cell>
|
||||
<DE.Label height="compact">
|
||||
No. Kartu BPJS
|
||||
<span class="text-red-500">*</span>
|
||||
</DE.Label>
|
||||
<DE.Field :errMessage="errors.cardNumber">
|
||||
<Input
|
||||
id="cardNumber"
|
||||
v-model="cardNumber"
|
||||
v-bind="cardNumberAttrs"
|
||||
:disabled="isLoading || isReadonly"
|
||||
placeholder="Masukkan nomor kartu BPJS"
|
||||
/>
|
||||
</DE.Field>
|
||||
<div
|
||||
v-if="isMemberValid"
|
||||
class="mt-1 flex items-center gap-2"
|
||||
>
|
||||
<Icon
|
||||
name="i-lucide-badge-check"
|
||||
class="h-4 w-4 bg-green-500 text-white"
|
||||
/>
|
||||
<span class="text-sm text-green-500">Aktif</span>
|
||||
</div>
|
||||
<div
|
||||
v-if="!isMemberValid"
|
||||
class="mt-1 flex items-center gap-2"
|
||||
>
|
||||
<Icon
|
||||
name="i-lucide-x"
|
||||
class="h-4 w-4 bg-red-500 text-white"
|
||||
/>
|
||||
<span class="text-sm text-red-500">Tidak aktif</span>
|
||||
</div>
|
||||
</DE.Cell>
|
||||
|
||||
<DE.Cell>
|
||||
<DE.Label height="compact">
|
||||
Jenis SEP
|
||||
<span class="text-red-500">*</span>
|
||||
</DE.Label>
|
||||
<DE.Field :errMessage="errors.sepType">
|
||||
<Select
|
||||
id="sepType"
|
||||
v-model="sepType"
|
||||
v-bind="sepTypeAttrs"
|
||||
:items="seps"
|
||||
:disabled="isLoading || isReadonly"
|
||||
placeholder="Pilih Jenis SEP"
|
||||
/>
|
||||
</DE.Field>
|
||||
</DE.Cell>
|
||||
</DE.Block>
|
||||
|
||||
<DE.Block
|
||||
labelSize="thin"
|
||||
class="!pt-0"
|
||||
:colCount="3"
|
||||
:cellFlex="false"
|
||||
>
|
||||
<DE.Cell>
|
||||
<DE.Label height="compact">
|
||||
No. SEP
|
||||
<span class="text-red-500">*</span>
|
||||
</DE.Label>
|
||||
<DE.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 || isSepValid"
|
||||
/>
|
||||
<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-if="isMemberValid"
|
||||
variant="outline"
|
||||
type="button"
|
||||
class="bg-primary"
|
||||
size="sm"
|
||||
@click="onSearchSep"
|
||||
>
|
||||
<Icon
|
||||
name="i-lucide-search"
|
||||
class="h-4 w-4"
|
||||
/>
|
||||
</Button>
|
||||
</div>
|
||||
</DE.Field>
|
||||
<div
|
||||
v-if="isSepValid"
|
||||
class="mt-1 flex items-center gap-2"
|
||||
>
|
||||
<Icon
|
||||
name="i-lucide-badge-check"
|
||||
class="h-4 w-4 bg-green-500 text-white"
|
||||
/>
|
||||
<span class="text-sm text-green-500">Aktif</span>
|
||||
</div>
|
||||
<span class="text-sm text-gray-500">
|
||||
{{ noteReference }}
|
||||
</span>
|
||||
</DE.Cell>
|
||||
|
||||
<DE.Cell>
|
||||
<FileUpload
|
||||
field-name="sepFile"
|
||||
label="Dokumen SEP"
|
||||
placeholder="Pilih file"
|
||||
:accept="['pdf', 'jpg', 'png']"
|
||||
:max-size-mb="1"
|
||||
v-model="sepFile"
|
||||
v-bind="sepFileAttrs"
|
||||
@file-selected="() => {}"
|
||||
/>
|
||||
<span class="mt-1 text-sm text-gray-500">
|
||||
{{ noteFile }}
|
||||
</span>
|
||||
<p v-if="sepFileReview">
|
||||
<a
|
||||
class="mt-1 text-sm capitalize text-blue-500"
|
||||
href="#"
|
||||
@click="openFile(sepFileReview.filePath)"
|
||||
>
|
||||
{{ sepFileReview?.fileName }}
|
||||
</a>
|
||||
</p>
|
||||
</DE.Cell>
|
||||
|
||||
<DE.Cell>
|
||||
<FileUpload
|
||||
field-name="sippFile"
|
||||
label="Dokumen SIPP"
|
||||
placeholder="Pilih file"
|
||||
:accept="['pdf', 'jpg', 'png']"
|
||||
:max-size-mb="1"
|
||||
v-model="sippFile"
|
||||
v-bind="sippFileAttrs"
|
||||
@file-selected="() => {}"
|
||||
/>
|
||||
<span class="mt-1 text-sm text-gray-500">
|
||||
{{ noteFile }}
|
||||
</span>
|
||||
<p v-if="sippFileReview">
|
||||
<a
|
||||
class="mt-1 text-sm capitalize text-blue-500"
|
||||
href="#"
|
||||
@click="openFile(sippFileReview.filePath)"
|
||||
>
|
||||
{{ sippFileReview?.fileName }}
|
||||
</a>
|
||||
</p>
|
||||
</DE.Cell>
|
||||
</DE.Block>
|
||||
</template>
|
||||
|
||||
<template v-if="isSepValid">
|
||||
<hr />
|
||||
<!-- Data SEP -->
|
||||
<h3 class="text-lg font-semibold">Data SEP</h3>
|
||||
|
||||
<DE.Block
|
||||
labelSize="thin"
|
||||
class="!pt-0"
|
||||
:colCount="3"
|
||||
:cellFlex="false"
|
||||
>
|
||||
<DE.Cell>
|
||||
<Label height="compact">Dengan Rujukan / Surat Kontrol</Label>
|
||||
<DE.Field>
|
||||
<Input
|
||||
id="sepReference"
|
||||
v-model="sepReference"
|
||||
:disabled="true"
|
||||
/>
|
||||
</DE.Field>
|
||||
</DE.Cell>
|
||||
|
||||
<DE.Cell>
|
||||
<Label height="compact">No. Rujukan / Surat Kontrol</Label>
|
||||
<DE.Field>
|
||||
<Input
|
||||
id="sepReference"
|
||||
v-model="sepNumber"
|
||||
:disabled="true"
|
||||
/>
|
||||
</DE.Field>
|
||||
</DE.Cell>
|
||||
|
||||
<DE.Cell>
|
||||
<Label height="compact">
|
||||
Tanggal Rujukan / Surat Kontrol
|
||||
<span class="ml-1 text-red-500">*</span>
|
||||
</Label>
|
||||
<DE.Field>
|
||||
<DatepickerSingle
|
||||
id="sepControlDate"
|
||||
v-model="sepControlDate"
|
||||
:disabled="true"
|
||||
placeholder="Pilih tanggal sep"
|
||||
/>
|
||||
</DE.Field>
|
||||
</DE.Cell>
|
||||
</DE.Block>
|
||||
|
||||
<DE.Block
|
||||
labelSize="thin"
|
||||
class="!pt-0"
|
||||
:colCount="3"
|
||||
:cellFlex="false"
|
||||
>
|
||||
<DE.Cell :col-span="2">
|
||||
<Label height="compact">Diagnosis</Label>
|
||||
<DE.Field>
|
||||
<Input
|
||||
id="diagnosis"
|
||||
v-model="diagnosis"
|
||||
:disabled="true"
|
||||
/>
|
||||
</DE.Field>
|
||||
</DE.Cell>
|
||||
|
||||
<DE.Cell>
|
||||
<Label height="compact">Status Kecelakaan</Label>
|
||||
<DE.Field>
|
||||
<Input
|
||||
id="sepTrafficStatus"
|
||||
v-model="sepTrafficStatus"
|
||||
:disabled="true"
|
||||
/>
|
||||
</DE.Field>
|
||||
</DE.Cell>
|
||||
</DE.Block>
|
||||
</template>
|
||||
</form>
|
||||
</div>
|
||||
</template>
|
||||
@@ -393,20 +393,31 @@ onMounted(() => {
|
||||
:colCount="3"
|
||||
:cellFlex="false"
|
||||
>
|
||||
{{ JSON.stringify(paymentMethodCode) }}
|
||||
{{ JSON.stringify(paymentMethodItems, null, 2) }}
|
||||
{{ JSON.stringify(payments, null, 2) }}
|
||||
<DE.Cell>
|
||||
<DE.Label height="compact">
|
||||
Jenis Pembayaran
|
||||
<span class="text-red-500">*</span>
|
||||
</DE.Label>
|
||||
<DE.Field :errMessage="errors.paymentMethod_code">
|
||||
<CB.Combobox
|
||||
<Select
|
||||
id="paymentMethodCode"
|
||||
v-model="paymentMethodCode"
|
||||
v-bind="paymentMethodCodeAttrs"
|
||||
:items="payments as any"
|
||||
:disabled="isLoading || isReadonly"
|
||||
placeholder="Pilih Jenis Pembayaran"
|
||||
/>
|
||||
<!-- <CB.Combobox
|
||||
id="paymentMethodCode"
|
||||
v-model="paymentMethodCode"
|
||||
v-bind="paymentMethodCodeAttrs"
|
||||
:items="paymentMethodItems"
|
||||
:disabled="isLoading || isReadonly"
|
||||
placeholder="Pilih Jenis Pembayaran"
|
||||
/>
|
||||
/> -->
|
||||
</DE.Field>
|
||||
</DE.Cell>
|
||||
</DE.Block>
|
||||
|
||||
@@ -188,6 +188,7 @@ onMounted(async () => {
|
||||
@event="handleEvent"
|
||||
@fetch="handleFetch"
|
||||
/>
|
||||
|
||||
<AppViewPatient
|
||||
v-model:open="openPatient"
|
||||
v-model:selected="selectedPatient"
|
||||
@@ -206,11 +207,13 @@ onMounted(async () => {
|
||||
"
|
||||
@save="handleSavePatient"
|
||||
/>
|
||||
|
||||
<AppViewHistory
|
||||
v-model:open="openHistory"
|
||||
:is-action="true"
|
||||
:histories="histories"
|
||||
/>
|
||||
|
||||
<!-- Footer Actions -->
|
||||
<div class="mt-6 flex justify-end gap-2 border-t border-t-slate-300 pt-4">
|
||||
<Button
|
||||
|
||||
+5
-12
@@ -19,25 +19,18 @@ export function usePageChecker() {
|
||||
) {
|
||||
// Check if user has access to this page, need to use try - catch for proper handling
|
||||
const hasAccess = checkRole(roleAccess)
|
||||
if (!hasAccess) {
|
||||
navigateTo('/403')
|
||||
}
|
||||
if (!hasAccess) return false
|
||||
|
||||
// Define permission-based computed properties
|
||||
const canCreate = hasCreateAccess(roleAccess)
|
||||
const canRead = hasReadAccess(roleAccess)
|
||||
const canUpdate = hasUpdateAccess(roleAccess)
|
||||
const canDelete = hasDeleteAccess(roleAccess)
|
||||
|
||||
switch (type) {
|
||||
case 'create':
|
||||
return canCreate
|
||||
return hasCreateAccess(roleAccess)
|
||||
case 'read':
|
||||
return canRead
|
||||
return hasReadAccess(roleAccess)
|
||||
case 'update':
|
||||
return canUpdate
|
||||
return hasUpdateAccess(roleAccess)
|
||||
case 'delete':
|
||||
return canDelete
|
||||
return hasDeleteAccess(roleAccess)
|
||||
default:
|
||||
return false
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user