mbois gak rek?
This commit is contained in:
No files matched your search
@@ -0,0 +1,468 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import { useForm } from 'vee-validate'
|
||||||
|
import { toTypedSchema } from '@vee-validate/zod'
|
||||||
|
import { type Duration, intervalToDuration } from 'date-fns'
|
||||||
|
|
||||||
|
// schema
|
||||||
|
import { type ActionReportFormData, ActionReportSchema } from '~/schemas/action-report.schema'
|
||||||
|
|
||||||
|
// type
|
||||||
|
import type { Doctor } from '~/models/doctor'
|
||||||
|
import { type ClickType as ActionClickType } from '~/components/pub/my-ui/nav-footer/index'
|
||||||
|
|
||||||
|
// components
|
||||||
|
import * as DE from '~/components/pub/my-ui/doc-entry'
|
||||||
|
import Separator from '~/components/pub/ui/separator/Separator.vue'
|
||||||
|
import { ArrayMessage } from '~/components/pub/ui/form'
|
||||||
|
import ActionForm from '~/components/pub/my-ui/nav-footer/ba-dr-su.vue'
|
||||||
|
|
||||||
|
// form field components
|
||||||
|
import {
|
||||||
|
FillNotes,
|
||||||
|
RadioBloods,
|
||||||
|
SelectBilling,
|
||||||
|
SelectBirthPlace,
|
||||||
|
SelectBirthType,
|
||||||
|
SelectOperationSystem,
|
||||||
|
SelectOperationType,
|
||||||
|
SelectSpecimen,
|
||||||
|
SelectSurgeryCounter,
|
||||||
|
SelectSurgeryType,
|
||||||
|
} from './fields'
|
||||||
|
import { ButtonAction, Fragment, InputBase, TextAreaInput } from '~/components/pub/my-ui/form/'
|
||||||
|
import { SelectDoctor } from '~/components/app/doctor/fields'
|
||||||
|
// Helpers
|
||||||
|
|
||||||
|
// #region Props & Emits
|
||||||
|
interface FormData extends ActionReportFormData {
|
||||||
|
_operationDuration: string
|
||||||
|
_anesthesiaDuration: string
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
isLoading: boolean
|
||||||
|
mode: 'add' | 'edit' | 'view'
|
||||||
|
initialValues?: Partial<FormData>
|
||||||
|
|
||||||
|
// form related
|
||||||
|
doctors: Doctor[]
|
||||||
|
}
|
||||||
|
|
||||||
|
const props = defineProps<Props>()
|
||||||
|
const emit = defineEmits<{
|
||||||
|
(e: 'submit', payload: FormData): void
|
||||||
|
(e: 'back'): void
|
||||||
|
(e: 'error', errors: Error): void
|
||||||
|
}>()
|
||||||
|
|
||||||
|
const tissueNotesLimit = 5
|
||||||
|
const mode = toRef(props, 'mode')
|
||||||
|
const isLoading = toRef(props, 'isLoading')
|
||||||
|
|
||||||
|
const isReadonly = computed(() => {
|
||||||
|
if (isLoading.value === true) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mode.value === 'view') {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
})
|
||||||
|
|
||||||
|
const formSchema = toTypedSchema(ActionReportSchema)
|
||||||
|
|
||||||
|
const { errors, handleSubmit, values, meta, resetForm, setFieldValue, setValues, validate } = useForm<FormData>({
|
||||||
|
name: 'encounterActionReportForm',
|
||||||
|
validationSchema: formSchema,
|
||||||
|
initialValues: props.initialValues ? props.initialValues : {},
|
||||||
|
validateOnMount: false,
|
||||||
|
})
|
||||||
|
|
||||||
|
defineExpose({
|
||||||
|
validate,
|
||||||
|
resetForm,
|
||||||
|
setValues,
|
||||||
|
values,
|
||||||
|
})
|
||||||
|
// #endregion
|
||||||
|
|
||||||
|
// #region State & Computed
|
||||||
|
// #endregion
|
||||||
|
|
||||||
|
// #region Lifecycle Hooks
|
||||||
|
// #endregion
|
||||||
|
|
||||||
|
// #region Functions
|
||||||
|
// #endregion region
|
||||||
|
|
||||||
|
// #region Utilities & event handlers
|
||||||
|
const onFormActionClicked = (action: ActionClickType) => {
|
||||||
|
if (action === 'back') {
|
||||||
|
emit('back')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (action === 'submit') {
|
||||||
|
onSubmit()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const onSubmit = handleSubmit(
|
||||||
|
(values) => {
|
||||||
|
console.log(JSON.stringify(values))
|
||||||
|
emit('submit', values)
|
||||||
|
},
|
||||||
|
(errors) => {
|
||||||
|
console.error(errors)
|
||||||
|
emit('error', new Error('Silahkan lengkapi form terlebih dahulu'))
|
||||||
|
},
|
||||||
|
)
|
||||||
|
// #endregion
|
||||||
|
|
||||||
|
// #region Watcher
|
||||||
|
watch(
|
||||||
|
() => [values.operationExecution.operationStartAt, values.operationExecution.operationEndAt],
|
||||||
|
([start, end]) => {
|
||||||
|
if (!start || !end) return
|
||||||
|
const pStart = new Date(start)
|
||||||
|
const pEnd = new Date(end)
|
||||||
|
|
||||||
|
const formatTime = (r: Duration) =>
|
||||||
|
[r.hours && `${r.hours} jam`, r.minutes && `${r.minutes} menit`, r.seconds && `${r.seconds} detik`]
|
||||||
|
.filter(Boolean)
|
||||||
|
.join(' ')
|
||||||
|
|
||||||
|
const res = intervalToDuration({
|
||||||
|
start: pStart,
|
||||||
|
end: pEnd,
|
||||||
|
})
|
||||||
|
|
||||||
|
setFieldValue('_operationDuration', formatTime(res))
|
||||||
|
},
|
||||||
|
{ immediate: true },
|
||||||
|
)
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => [values.operationExecution.anesthesiaStartAt, values.operationExecution.anesthesiaEndAt],
|
||||||
|
([start, end]) => {
|
||||||
|
if (!start || !end) return
|
||||||
|
const pStart = new Date(start)
|
||||||
|
const pEnd = new Date(end)
|
||||||
|
|
||||||
|
const formatTime = (r: Duration) =>
|
||||||
|
[r.hours && `${r.hours} jam`, r.minutes && `${r.minutes} menit`, r.seconds && `${r.seconds} detik`]
|
||||||
|
.filter(Boolean)
|
||||||
|
.join(' ')
|
||||||
|
|
||||||
|
const res = intervalToDuration({
|
||||||
|
start: pStart,
|
||||||
|
end: pEnd,
|
||||||
|
})
|
||||||
|
|
||||||
|
setFieldValue('_anesthesiaDuration', formatTime(res))
|
||||||
|
},
|
||||||
|
{ immediate: true },
|
||||||
|
)
|
||||||
|
// #endregion
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<form @submit.prevent="onSubmit">
|
||||||
|
<Fragment
|
||||||
|
v-slot="{ section }"
|
||||||
|
title="Tim Pelaksana Tindakan"
|
||||||
|
>
|
||||||
|
<p class="text-lg font-semibold">{{ section }}</p>
|
||||||
|
|
||||||
|
<DE.Block
|
||||||
|
:col-count="4"
|
||||||
|
:cell-flex="false"
|
||||||
|
>
|
||||||
|
<SelectDoctor
|
||||||
|
fieldName="operatorTeam.dpjpId"
|
||||||
|
label="Dokter Pemeriksa"
|
||||||
|
placeholder="Pilih dokter"
|
||||||
|
:doctors="doctors"
|
||||||
|
:is-disabled="isReadonly"
|
||||||
|
/>
|
||||||
|
<InputBase
|
||||||
|
field-name="operatorTeam.operatorName"
|
||||||
|
label="Operator"
|
||||||
|
placeholder="Masukkan operator"
|
||||||
|
:is-disabled="isReadonly"
|
||||||
|
/>
|
||||||
|
<InputBase
|
||||||
|
field-name="operatorTeam.assistantOperatorName"
|
||||||
|
label="Asisten Operator"
|
||||||
|
placeholder="Masukkan asisten operator"
|
||||||
|
:is-disabled="isReadonly"
|
||||||
|
/>
|
||||||
|
<InputBase
|
||||||
|
field-name="operatorTeam.instrumentNurseName"
|
||||||
|
label="Instrumentir"
|
||||||
|
placeholder="Masukkan instrumentir"
|
||||||
|
:is-disabled="isReadonly"
|
||||||
|
/>
|
||||||
|
<InputBase
|
||||||
|
field-name="operatorTeam.surgeryDate"
|
||||||
|
label="Tanggal Pembedahan"
|
||||||
|
input-type="datetime-local"
|
||||||
|
:is-disabled="isReadonly"
|
||||||
|
placeholder=""
|
||||||
|
/>
|
||||||
|
</DE.Block>
|
||||||
|
<DE.Block
|
||||||
|
:col-count="4"
|
||||||
|
:cell-flex="false"
|
||||||
|
>
|
||||||
|
<TextAreaInput
|
||||||
|
field-name="operatorTeam.actionDiagnosis"
|
||||||
|
label="Diagnosa Tindakan"
|
||||||
|
placeholder="Masukkan diagnosa tindakan"
|
||||||
|
:col-span="2"
|
||||||
|
:rows="5"
|
||||||
|
:is-disabled="isReadonly"
|
||||||
|
/>
|
||||||
|
<InputBase
|
||||||
|
field-name="operatorTeam.postSurgeryNurseId"
|
||||||
|
label="Perawat Pasca Bedah"
|
||||||
|
placeholder="Masukkan perawat pasca bedah"
|
||||||
|
:is-disabled="isReadonly"
|
||||||
|
/>
|
||||||
|
</DE.Block>
|
||||||
|
</Fragment>
|
||||||
|
|
||||||
|
<Separator class="my-4" />
|
||||||
|
|
||||||
|
<Fragment
|
||||||
|
v-slot="{ section }"
|
||||||
|
title="Tindakan Operatif/Non Operatif Lain"
|
||||||
|
>
|
||||||
|
<!-- <p class="text-lg font-semibold">{{ section }}</p> -->
|
||||||
|
<DE.Block
|
||||||
|
:col-count="2"
|
||||||
|
:cell-flex="false"
|
||||||
|
>
|
||||||
|
<DE.Cell>
|
||||||
|
<slot name="procedures" />
|
||||||
|
<ArrayMessage
|
||||||
|
class="mt-1"
|
||||||
|
v-if="meta.touched"
|
||||||
|
name="procedures"
|
||||||
|
/>
|
||||||
|
</DE.Cell>
|
||||||
|
</DE.Block>
|
||||||
|
</Fragment>
|
||||||
|
|
||||||
|
<Separator class="my-4" />
|
||||||
|
|
||||||
|
<Fragment
|
||||||
|
v-slot="{ section }"
|
||||||
|
title="Data Pelaksanaan Operasi"
|
||||||
|
>
|
||||||
|
<p class="text-lg font-semibold">{{ section }}</p>
|
||||||
|
|
||||||
|
<DE.Block
|
||||||
|
:col-count="3"
|
||||||
|
:cell-flex="false"
|
||||||
|
>
|
||||||
|
<SelectSurgeryType
|
||||||
|
field-name="operationExecution.surgeryType"
|
||||||
|
label="Jenis Operasi"
|
||||||
|
placeholder="Pilih jenis operasi"
|
||||||
|
:is-disabled="isReadonly"
|
||||||
|
/>
|
||||||
|
<SelectBilling
|
||||||
|
field-name="operationExecution.billingCode"
|
||||||
|
label="Kode Billing"
|
||||||
|
placeholder="Pilih kode billing"
|
||||||
|
:is-disabled="isReadonly"
|
||||||
|
/>
|
||||||
|
<SelectOperationSystem
|
||||||
|
field-name="operationExecution.operationSystem"
|
||||||
|
label="Sistem Operasi"
|
||||||
|
placeholder="Pilih sistem operasi"
|
||||||
|
:is-disabled="isReadonly"
|
||||||
|
/>
|
||||||
|
</DE.Block>
|
||||||
|
|
||||||
|
<DE.Block
|
||||||
|
:col-count="3"
|
||||||
|
:cell-flex="false"
|
||||||
|
>
|
||||||
|
<InputBase
|
||||||
|
field-name="operationExecution.operationStartAt"
|
||||||
|
label="Operasi Mulai"
|
||||||
|
placeholder="Pilih Tanggal"
|
||||||
|
input-type="datetime-local"
|
||||||
|
:is-disabled="isReadonly"
|
||||||
|
/>
|
||||||
|
<InputBase
|
||||||
|
field-name="operationExecution.operationEndAt"
|
||||||
|
label="Operasi Selesai"
|
||||||
|
placeholder="Pilih Tanggal"
|
||||||
|
input-type="datetime-local"
|
||||||
|
:is-disabled="isReadonly"
|
||||||
|
/>
|
||||||
|
<InputBase
|
||||||
|
field-name="_operationDuration"
|
||||||
|
label="Lama Operasi"
|
||||||
|
placeholder="-"
|
||||||
|
is-disabled
|
||||||
|
/>
|
||||||
|
</DE.Block>
|
||||||
|
|
||||||
|
<DE.Block
|
||||||
|
:col-count="3"
|
||||||
|
:cell-flex="false"
|
||||||
|
>
|
||||||
|
<InputBase
|
||||||
|
field-name="operationExecution.anesthesiaStartAt"
|
||||||
|
label="Pembiusan Mulai"
|
||||||
|
placeholder="Pilih Tanggal"
|
||||||
|
input-type="datetime-local"
|
||||||
|
:is-disabled="isReadonly"
|
||||||
|
/>
|
||||||
|
<InputBase
|
||||||
|
field-name="operationExecution.anesthesiaEndAt"
|
||||||
|
label="Pembiusan Selesai"
|
||||||
|
placeholder="Pilih Tanggal"
|
||||||
|
input-type="datetime-local"
|
||||||
|
:is-disabled="isReadonly"
|
||||||
|
/>
|
||||||
|
<InputBase
|
||||||
|
field-name="_anesthesiaDuration"
|
||||||
|
label="Lama Pembiusan"
|
||||||
|
placeholder="-"
|
||||||
|
is-disabled
|
||||||
|
/>
|
||||||
|
</DE.Block>
|
||||||
|
|
||||||
|
<DE.Block
|
||||||
|
:col-count="3"
|
||||||
|
:cell-flex="false"
|
||||||
|
>
|
||||||
|
<SelectOperationType
|
||||||
|
field-name="operationExecution.surgeryCleanType"
|
||||||
|
label="Jenis Pembedahan"
|
||||||
|
placeholder="Pilih jenis pembedahan"
|
||||||
|
:is-disabled="isReadonly"
|
||||||
|
/>
|
||||||
|
<SelectSurgeryCounter
|
||||||
|
field-name="operationExecution.surgeryNumber"
|
||||||
|
label="Operasi Ke"
|
||||||
|
placeholder="Pilih"
|
||||||
|
:is-disabled="isReadonly"
|
||||||
|
/>
|
||||||
|
<SelectBirthType
|
||||||
|
field-name="operationExecution.birthRemark"
|
||||||
|
label="Keterangan Lahir"
|
||||||
|
placeholder="Pilih"
|
||||||
|
:is-disabled="isReadonly"
|
||||||
|
/>
|
||||||
|
<SelectBirthPlace
|
||||||
|
field-name="operationExecution.birthPlaceNote"
|
||||||
|
label="Ket. Tempat Lahir"
|
||||||
|
placeholder="Pilih keterangan tempat lahir"
|
||||||
|
:is-disabled="isReadonly"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<InputBase
|
||||||
|
field-name="operationExecution.personWeight"
|
||||||
|
label="Berat Badan"
|
||||||
|
placeholder="Masukkan berat badan"
|
||||||
|
numeric-only
|
||||||
|
suffix-msg="Gram"
|
||||||
|
:is-disabled="isReadonly"
|
||||||
|
/>
|
||||||
|
<InputBase
|
||||||
|
field-name="operationExecution.birthCondition"
|
||||||
|
label="Ket. Saat Lahir"
|
||||||
|
placeholder="Tambah catatan"
|
||||||
|
:is-disabled="isReadonly"
|
||||||
|
/>
|
||||||
|
</DE.Block>
|
||||||
|
|
||||||
|
<DE.Block
|
||||||
|
:col-count="4"
|
||||||
|
:cell-flex="false"
|
||||||
|
>
|
||||||
|
<TextAreaInput
|
||||||
|
field-name="operationExecution.operationDescription"
|
||||||
|
label="Uraian Operasi"
|
||||||
|
placeholder="Masukkan uraian"
|
||||||
|
:rows="3"
|
||||||
|
:col-span="2"
|
||||||
|
:is-disabled="isReadonly"
|
||||||
|
/>
|
||||||
|
<InputBase
|
||||||
|
field-name="operationExecution.bleedingAmountCc"
|
||||||
|
label="Jumlah Pendarahan"
|
||||||
|
placeholder="Masukkan jumlah pendarahan"
|
||||||
|
suffix-msg="CC"
|
||||||
|
numeric-only
|
||||||
|
:is-disabled="isReadonly"
|
||||||
|
/>
|
||||||
|
</DE.Block>
|
||||||
|
<DE.Block
|
||||||
|
:col-count="3"
|
||||||
|
:cell-flex="false"
|
||||||
|
>
|
||||||
|
<RadioBloods
|
||||||
|
field-name="bloodInput"
|
||||||
|
label="Jenis & Jumlah Darah Masuk"
|
||||||
|
:is-disabled="isReadonly"
|
||||||
|
/>
|
||||||
|
</DE.Block>
|
||||||
|
|
||||||
|
<DE.Block
|
||||||
|
:col-count="3"
|
||||||
|
:cell-flex="false"
|
||||||
|
>
|
||||||
|
<InputBase
|
||||||
|
field-name="implant.brand"
|
||||||
|
label="Merk"
|
||||||
|
placeholder="Masukkan merk"
|
||||||
|
:is-disabled="isReadonly"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<InputBase
|
||||||
|
field-name="implant.name"
|
||||||
|
label="Nama Implant"
|
||||||
|
placeholder="Masukkan nama implant"
|
||||||
|
:is-disabled="isReadonly"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<InputBase
|
||||||
|
field-name="implant.sticker"
|
||||||
|
label="Sticker/Nomer Register Implant"
|
||||||
|
placeholder="Masukkan sticker/nomor register implant"
|
||||||
|
:is-disabled="isReadonly"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<InputBase
|
||||||
|
field-name="implant.companionName"
|
||||||
|
label="Nama Pendamping Implant"
|
||||||
|
placeholder="Masukkan nama pendamping implant"
|
||||||
|
:is-disabled="isReadonly"
|
||||||
|
/>
|
||||||
|
<SelectSpecimen
|
||||||
|
field-name="specimen.destination"
|
||||||
|
label="Specimen/Jaringan dikirim ke"
|
||||||
|
placeholder="Pilih"
|
||||||
|
:is-disabled="isReadonly"
|
||||||
|
/>
|
||||||
|
</DE.Block>
|
||||||
|
<FillNotes
|
||||||
|
title="Keterangan Jaringan"
|
||||||
|
:limit="tissueNotesLimit"
|
||||||
|
:is-disabled="isReadonly"
|
||||||
|
/>
|
||||||
|
</Fragment>
|
||||||
|
<div class="mt-4 flex justify-end">
|
||||||
|
<ActionForm @click="onFormActionClicked" />
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</template>
|
||||||
@@ -0,0 +1,65 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
// components
|
||||||
|
import { FieldArray } from 'vee-validate'
|
||||||
|
import * as DE from '~/components/pub/my-ui/doc-entry'
|
||||||
|
|
||||||
|
// form field components
|
||||||
|
import { ButtonAction, InputBase } from '~/components/pub/my-ui/form'
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
isDisabled: boolean
|
||||||
|
limit: number
|
||||||
|
title: string
|
||||||
|
}
|
||||||
|
|
||||||
|
const props = defineProps<Props>()
|
||||||
|
|
||||||
|
const isReadonly = computed(() => props.isDisabled)
|
||||||
|
</script>
|
||||||
|
<template>
|
||||||
|
<FieldArray
|
||||||
|
v-slot="{ fields, push, remove }"
|
||||||
|
name="tissueNotes"
|
||||||
|
>
|
||||||
|
<template v-if="fields.length === 0">
|
||||||
|
{{ push({ note: '' }) }}
|
||||||
|
</template>
|
||||||
|
<div class="space-y-4">
|
||||||
|
<DE.Block
|
||||||
|
v-for="(field, idx) in fields"
|
||||||
|
:key="field.key"
|
||||||
|
:col-count="3"
|
||||||
|
:cell-flex="false"
|
||||||
|
>
|
||||||
|
<InputBase
|
||||||
|
:label="idx === 0 ? 'Keterangan Jaringan' : undefined"
|
||||||
|
:field-name="`tissueNotes[${idx}].note`"
|
||||||
|
placeholder="Masukkan catatan"
|
||||||
|
:is-disabled="isReadonly"
|
||||||
|
/>
|
||||||
|
<DE.Cell class="flex items-start justify-start">
|
||||||
|
<DE.Field :class="idx === 0 ? 'mt-[30px]' : 'mt-0'">
|
||||||
|
<ButtonAction
|
||||||
|
v-if="idx !== 0"
|
||||||
|
:disabled="isReadonly"
|
||||||
|
preset="delete"
|
||||||
|
:title="`Hapus Kontak ${idx + 1}`"
|
||||||
|
icon-only
|
||||||
|
@click="remove(idx)"
|
||||||
|
/>
|
||||||
|
</DE.Field>
|
||||||
|
</DE.Cell>
|
||||||
|
</DE.Block>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<ButtonAction
|
||||||
|
preset="add"
|
||||||
|
label="Tambah Catatan"
|
||||||
|
title="Tambah Catatan Keterangan Jaringan"
|
||||||
|
:disabled="fields.length >= limit || isReadonly"
|
||||||
|
:full-width-mobile="true"
|
||||||
|
class="mt-4"
|
||||||
|
@click="push({ name: '', dose: '', unit: '' })"
|
||||||
|
/>
|
||||||
|
</FieldArray>
|
||||||
|
</template>
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
export { default as FillNotes } from './fill-notes.vue'
|
||||||
|
export { default as RadioBloods } from './radio-bloods.vue'
|
||||||
|
export { default as SelectBilling } from './select-billing.vue'
|
||||||
|
export { default as SelectBirthPlace } from './select-birth-place.vue'
|
||||||
|
export { default as SelectBirthType } from './select-birth-type.vue'
|
||||||
|
export { default as SelectOperationSystem } from './select-operation-system.vue'
|
||||||
|
export { default as SelectOperationType } from './select-operation-type.vue'
|
||||||
|
export { default as SelectSpecimen } from './select-specimen.vue'
|
||||||
|
export { default as SelectSurgeryCounter } from './select-surgery-counter.vue'
|
||||||
|
export { default as SelectSurgeryType } from './select-surgery-type.vue'
|
||||||
@@ -0,0 +1,101 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import { cn } from '~/lib/utils'
|
||||||
|
|
||||||
|
import * as DE from '~/components/pub/my-ui/doc-entry'
|
||||||
|
import { RadioGroup, RadioGroupItem } from '~/components/pub/ui/radio-group'
|
||||||
|
import { Label as RadioLabel } from '~/components/pub/ui/label'
|
||||||
|
import { Input } from '~/components/pub/ui/input'
|
||||||
|
|
||||||
|
const props = defineProps<{
|
||||||
|
fieldName: string
|
||||||
|
label: string
|
||||||
|
class?: string
|
||||||
|
radioGroupClass?: string
|
||||||
|
radioItemClass?: string
|
||||||
|
labelClass?: string
|
||||||
|
isDisabled?: boolean
|
||||||
|
}>()
|
||||||
|
|
||||||
|
const { class: containerClass, radioGroupClass, radioItemClass, labelClass } = props
|
||||||
|
|
||||||
|
const opts = [
|
||||||
|
{ label: 'PRC', value: 'prc' },
|
||||||
|
{ label: 'WB', value: 'wb' },
|
||||||
|
{ label: 'FFP', value: 'ffp' },
|
||||||
|
{ label: 'TC', value: 'tc' },
|
||||||
|
]
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<DE.Cell
|
||||||
|
:class="cn('radio-group-field', containerClass)"
|
||||||
|
:col-span="2"
|
||||||
|
>
|
||||||
|
<DE.Label :label-for="fieldName">
|
||||||
|
{{ label }}
|
||||||
|
</DE.Label>
|
||||||
|
<DE.Field :id="fieldName">
|
||||||
|
<FormField
|
||||||
|
v-slot="{ componentField: radioField }"
|
||||||
|
:name="`${fieldName}.type`"
|
||||||
|
>
|
||||||
|
<FormItem>
|
||||||
|
<FormControl>
|
||||||
|
<RadioGroup
|
||||||
|
:model-value="radioField.modelValue"
|
||||||
|
@update:model-value="radioField.onChange"
|
||||||
|
:class="cn('grid grid-cols-1 items-start gap-4 sm:grid-cols-2 ', radioGroupClass)"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
v-for="(option, index) in opts"
|
||||||
|
:key="option.value"
|
||||||
|
:class="cn('grid grid-cols-1 items-start gap-3 sm:grid-cols-[auto,1fr]', radioItemClass)"
|
||||||
|
>
|
||||||
|
<div class="flex min-w-fit items-center gap-2">
|
||||||
|
<RadioGroupItem
|
||||||
|
:id="`type-${index}`"
|
||||||
|
:value="option.value"
|
||||||
|
:disabled="isDisabled"
|
||||||
|
/>
|
||||||
|
<RadioLabel :for="`type-${index}`">
|
||||||
|
{{ option.label }}
|
||||||
|
</RadioLabel>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<FormField
|
||||||
|
v-slot="{ componentField: amountField }"
|
||||||
|
:name="`${fieldName}.amount.${option.value}`"
|
||||||
|
>
|
||||||
|
<FormItem>
|
||||||
|
<FormControl>
|
||||||
|
<div class="relative w-[140px]">
|
||||||
|
<Input
|
||||||
|
v-bind="amountField"
|
||||||
|
placeholder="00"
|
||||||
|
class="pr-10"
|
||||||
|
:disabled="radioField.modelValue !== option.value || isDisabled"
|
||||||
|
@input="
|
||||||
|
(e: InputEvent) => {
|
||||||
|
const target = e.target as HTMLInputElement
|
||||||
|
const v = target.value.replace(/\D/g, '')
|
||||||
|
amountField.onChange(v)
|
||||||
|
}
|
||||||
|
"
|
||||||
|
/>
|
||||||
|
<span
|
||||||
|
class="absolute inset-y-0 end-0 flex items-center justify-center px-2 text-sm text-muted-foreground"
|
||||||
|
>
|
||||||
|
CC
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</FormControl>
|
||||||
|
</FormItem>
|
||||||
|
</FormField>
|
||||||
|
</div>
|
||||||
|
</RadioGroup>
|
||||||
|
</FormControl>
|
||||||
|
</FormItem>
|
||||||
|
</FormField>
|
||||||
|
</DE.Field>
|
||||||
|
</DE.Cell>
|
||||||
|
</template>
|
||||||
@@ -0,0 +1,68 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import type { FormErrors } from '~/types/error'
|
||||||
|
import Select from '~/components/pub/my-ui/form/select.vue'
|
||||||
|
import { cn } from '~/lib/utils'
|
||||||
|
|
||||||
|
import * as DE from '~/components/pub/my-ui/doc-entry'
|
||||||
|
|
||||||
|
const props = defineProps<{
|
||||||
|
fieldName: string
|
||||||
|
label: string
|
||||||
|
isDisabled?: boolean
|
||||||
|
isRequired?: boolean
|
||||||
|
placeholder?: string
|
||||||
|
errors?: FormErrors
|
||||||
|
class?: string
|
||||||
|
selectClass?: string
|
||||||
|
fieldGroupClass?: string
|
||||||
|
}>()
|
||||||
|
|
||||||
|
const { errors, class: containerClass, selectClass, fieldGroupClass } = props
|
||||||
|
|
||||||
|
const opts = [
|
||||||
|
{ label: 'General', value: 'general' },
|
||||||
|
{ label: 'Regional', value: 'regional' },
|
||||||
|
{ label: 'Local', value: 'local' },
|
||||||
|
]
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<DE.Cell :class="cn('select-field-group', fieldGroupClass, containerClass)">
|
||||||
|
<DE.Label
|
||||||
|
label-for="fieldName"
|
||||||
|
:is-required="isRequired"
|
||||||
|
>
|
||||||
|
{{ label }}
|
||||||
|
</DE.Label>
|
||||||
|
<DE.Field
|
||||||
|
:id="fieldName"
|
||||||
|
:errors="errors"
|
||||||
|
:class="cn('select-field-wrapper')"
|
||||||
|
>
|
||||||
|
<FormField
|
||||||
|
v-slot="{ componentField }"
|
||||||
|
:name="fieldName"
|
||||||
|
>
|
||||||
|
<FormItem>
|
||||||
|
<FormControl>
|
||||||
|
<Select
|
||||||
|
:id="fieldName"
|
||||||
|
:is-disabled="isDisabled"
|
||||||
|
v-bind="componentField"
|
||||||
|
:items="opts"
|
||||||
|
:placeholder="placeholder"
|
||||||
|
:preserve-order="false"
|
||||||
|
:class="
|
||||||
|
cn(
|
||||||
|
'text-sm transition-all duration-200 focus:outline-none focus:ring-1 focus:ring-black focus:ring-offset-0',
|
||||||
|
selectClass,
|
||||||
|
)
|
||||||
|
"
|
||||||
|
/>
|
||||||
|
</FormControl>
|
||||||
|
<FormMessage />
|
||||||
|
</FormItem>
|
||||||
|
</FormField>
|
||||||
|
</DE.Field>
|
||||||
|
</DE.Cell>
|
||||||
|
</template>
|
||||||
@@ -0,0 +1,71 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import type { FormErrors } from '~/types/error'
|
||||||
|
import Select from '~/components/pub/my-ui/form/select.vue'
|
||||||
|
import { cn } from '~/lib/utils'
|
||||||
|
|
||||||
|
import * as DE from '~/components/pub/my-ui/doc-entry'
|
||||||
|
|
||||||
|
const props = defineProps<{
|
||||||
|
fieldName: string
|
||||||
|
label: string
|
||||||
|
isDisabled?: boolean
|
||||||
|
isRequired?: boolean
|
||||||
|
placeholder?: string
|
||||||
|
errors?: FormErrors
|
||||||
|
class?: string
|
||||||
|
selectClass?: string
|
||||||
|
fieldGroupClass?: string
|
||||||
|
}>()
|
||||||
|
|
||||||
|
const { errors, class: containerClass, selectClass, fieldGroupClass } = props
|
||||||
|
|
||||||
|
const opts = [
|
||||||
|
{ label: 'RSSA', value: 'rssa' },
|
||||||
|
{ label: 'Bidan Luar', value: 'out1' },
|
||||||
|
{ label: 'Dokter Luar', value: 'out2' },
|
||||||
|
{ label: 'Dukun Bayi', value: 'out3' },
|
||||||
|
{ label: 'Puskesmas', value: 'out4' },
|
||||||
|
{ label: 'Paramedis Luar', value: 'out5' },
|
||||||
|
]
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<DE.Cell :class="cn('select-field-group', fieldGroupClass, containerClass)">
|
||||||
|
<DE.Label
|
||||||
|
label-for="fieldName"
|
||||||
|
:is-required="isRequired"
|
||||||
|
>
|
||||||
|
{{ label }}
|
||||||
|
</DE.Label>
|
||||||
|
<DE.Field
|
||||||
|
:id="fieldName"
|
||||||
|
:errors="errors"
|
||||||
|
:class="cn('select-field-wrapper')"
|
||||||
|
>
|
||||||
|
<FormField
|
||||||
|
v-slot="{ componentField }"
|
||||||
|
:name="fieldName"
|
||||||
|
>
|
||||||
|
<FormItem>
|
||||||
|
<FormControl>
|
||||||
|
<Select
|
||||||
|
:id="fieldName"
|
||||||
|
:is-disabled="isDisabled"
|
||||||
|
v-bind="componentField"
|
||||||
|
:items="opts"
|
||||||
|
:placeholder="placeholder"
|
||||||
|
:preserve-order="false"
|
||||||
|
:class="
|
||||||
|
cn(
|
||||||
|
'text-sm transition-all duration-200 focus:outline-none focus:ring-1 focus:ring-black focus:ring-offset-0',
|
||||||
|
selectClass,
|
||||||
|
)
|
||||||
|
"
|
||||||
|
/>
|
||||||
|
</FormControl>
|
||||||
|
<FormMessage />
|
||||||
|
</FormItem>
|
||||||
|
</FormField>
|
||||||
|
</DE.Field>
|
||||||
|
</DE.Cell>
|
||||||
|
</template>
|
||||||
@@ -0,0 +1,67 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import type { FormErrors } from '~/types/error'
|
||||||
|
import Select from '~/components/pub/my-ui/form/select.vue'
|
||||||
|
import { cn } from '~/lib/utils'
|
||||||
|
|
||||||
|
import * as DE from '~/components/pub/my-ui/doc-entry'
|
||||||
|
|
||||||
|
const props = defineProps<{
|
||||||
|
fieldName: string
|
||||||
|
label: string
|
||||||
|
isDisabled?: boolean
|
||||||
|
isRequired?: boolean
|
||||||
|
placeholder?: string
|
||||||
|
errors?: FormErrors
|
||||||
|
class?: string
|
||||||
|
selectClass?: string
|
||||||
|
fieldGroupClass?: string
|
||||||
|
}>()
|
||||||
|
|
||||||
|
const { errors, class: containerClass, selectClass, fieldGroupClass } = props
|
||||||
|
|
||||||
|
const opts = [
|
||||||
|
{ label: 'Lahir Hidup', value: 'lahir_hidup' },
|
||||||
|
{ label: 'Lahir Mati', value: 'lahir_mati' },
|
||||||
|
]
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<DE.Cell :class="cn('select-field-group', fieldGroupClass, containerClass)">
|
||||||
|
<DE.Label
|
||||||
|
label-for="fieldName"
|
||||||
|
:is-required="isRequired"
|
||||||
|
>
|
||||||
|
{{ label }}
|
||||||
|
</DE.Label>
|
||||||
|
<DE.Field
|
||||||
|
:id="fieldName"
|
||||||
|
:errors="errors"
|
||||||
|
:class="cn('select-field-wrapper')"
|
||||||
|
>
|
||||||
|
<FormField
|
||||||
|
v-slot="{ componentField }"
|
||||||
|
:name="fieldName"
|
||||||
|
>
|
||||||
|
<FormItem>
|
||||||
|
<FormControl>
|
||||||
|
<Select
|
||||||
|
:id="fieldName"
|
||||||
|
:is-disabled="isDisabled"
|
||||||
|
v-bind="componentField"
|
||||||
|
:items="opts"
|
||||||
|
:placeholder="placeholder"
|
||||||
|
:preserve-order="false"
|
||||||
|
:class="
|
||||||
|
cn(
|
||||||
|
'text-sm transition-all duration-200 focus:outline-none focus:ring-1 focus:ring-black focus:ring-offset-0',
|
||||||
|
selectClass,
|
||||||
|
)
|
||||||
|
"
|
||||||
|
/>
|
||||||
|
</FormControl>
|
||||||
|
<FormMessage />
|
||||||
|
</FormItem>
|
||||||
|
</FormField>
|
||||||
|
</DE.Field>
|
||||||
|
</DE.Cell>
|
||||||
|
</template>
|
||||||
@@ -0,0 +1,69 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import type { FormErrors } from '~/types/error'
|
||||||
|
import Select from '~/components/pub/my-ui/form/select.vue'
|
||||||
|
import { cn } from '~/lib/utils'
|
||||||
|
|
||||||
|
import * as DE from '~/components/pub/my-ui/doc-entry'
|
||||||
|
|
||||||
|
const props = defineProps<{
|
||||||
|
fieldName: string
|
||||||
|
label: string
|
||||||
|
isDisabled?: boolean
|
||||||
|
isRequired?: boolean
|
||||||
|
placeholder?: string
|
||||||
|
errors?: FormErrors
|
||||||
|
class?: string
|
||||||
|
selectClass?: string
|
||||||
|
fieldGroupClass?: string
|
||||||
|
}>()
|
||||||
|
|
||||||
|
const { errors, class: containerClass, selectClass, fieldGroupClass } = props
|
||||||
|
|
||||||
|
const opts = [
|
||||||
|
{ label: 'Cito', value: 'cito' },
|
||||||
|
{ label: 'Urgent', value: 'urgent' },
|
||||||
|
{ label: 'Efektif', value: 'efektif' },
|
||||||
|
{ label: 'Khusus', value: 'khusus' },
|
||||||
|
]
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<DE.Cell :class="cn('select-field-group', fieldGroupClass, containerClass)">
|
||||||
|
<DE.Label
|
||||||
|
label-for="fieldName"
|
||||||
|
:is-required="isRequired"
|
||||||
|
>
|
||||||
|
{{ label }}
|
||||||
|
</DE.Label>
|
||||||
|
<DE.Field
|
||||||
|
:id="fieldName"
|
||||||
|
:errors="errors"
|
||||||
|
:class="cn('select-field-wrapper')"
|
||||||
|
>
|
||||||
|
<FormField
|
||||||
|
v-slot="{ componentField }"
|
||||||
|
:name="fieldName"
|
||||||
|
>
|
||||||
|
<FormItem>
|
||||||
|
<FormControl>
|
||||||
|
<Select
|
||||||
|
:id="fieldName"
|
||||||
|
:is-disabled="isDisabled"
|
||||||
|
v-bind="componentField"
|
||||||
|
:items="opts"
|
||||||
|
:placeholder="placeholder"
|
||||||
|
:preserve-order="false"
|
||||||
|
:class="
|
||||||
|
cn(
|
||||||
|
'text-sm transition-all duration-200 focus:outline-none focus:ring-1 focus:ring-black focus:ring-offset-0',
|
||||||
|
selectClass,
|
||||||
|
)
|
||||||
|
"
|
||||||
|
/>
|
||||||
|
</FormControl>
|
||||||
|
<FormMessage />
|
||||||
|
</FormItem>
|
||||||
|
</FormField>
|
||||||
|
</DE.Field>
|
||||||
|
</DE.Cell>
|
||||||
|
</template>
|
||||||
@@ -0,0 +1,69 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import type { FormErrors } from '~/types/error'
|
||||||
|
import Select from '~/components/pub/my-ui/form/select.vue'
|
||||||
|
import { cn } from '~/lib/utils'
|
||||||
|
|
||||||
|
import * as DE from '~/components/pub/my-ui/doc-entry'
|
||||||
|
|
||||||
|
const props = defineProps<{
|
||||||
|
fieldName: string
|
||||||
|
label: string
|
||||||
|
isDisabled?: boolean
|
||||||
|
isRequired?: boolean
|
||||||
|
placeholder?: string
|
||||||
|
errors?: FormErrors
|
||||||
|
class?: string
|
||||||
|
selectClass?: string
|
||||||
|
fieldGroupClass?: string
|
||||||
|
}>()
|
||||||
|
|
||||||
|
const { errors, class: containerClass, selectClass, fieldGroupClass } = props
|
||||||
|
|
||||||
|
const opts = [
|
||||||
|
{ label: 'Bersih', value: 'bersih' },
|
||||||
|
{ label: 'Bersih Terkontaminasi', value: 'bersih_terkontaminasi' },
|
||||||
|
{ label: 'Terkontaminasi Kotor', value: 'terkontaminasi' },
|
||||||
|
{ label: 'Kotor', value: 'kotor' },
|
||||||
|
]
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<DE.Cell :class="cn('select-field-group', fieldGroupClass, containerClass)">
|
||||||
|
<DE.Label
|
||||||
|
label-for="fieldName"
|
||||||
|
:is-required="isRequired"
|
||||||
|
>
|
||||||
|
{{ label }}
|
||||||
|
</DE.Label>
|
||||||
|
<DE.Field
|
||||||
|
:id="fieldName"
|
||||||
|
:errors="errors"
|
||||||
|
:class="cn('select-field-wrapper')"
|
||||||
|
>
|
||||||
|
<FormField
|
||||||
|
v-slot="{ componentField }"
|
||||||
|
:name="fieldName"
|
||||||
|
>
|
||||||
|
<FormItem>
|
||||||
|
<FormControl>
|
||||||
|
<Select
|
||||||
|
:id="fieldName"
|
||||||
|
:is-disabled="isDisabled"
|
||||||
|
v-bind="componentField"
|
||||||
|
:items="opts"
|
||||||
|
:placeholder="placeholder"
|
||||||
|
:preserve-order="false"
|
||||||
|
:class="
|
||||||
|
cn(
|
||||||
|
'text-sm transition-all duration-200 focus:outline-none focus:ring-1 focus:ring-black focus:ring-offset-0',
|
||||||
|
selectClass,
|
||||||
|
)
|
||||||
|
"
|
||||||
|
/>
|
||||||
|
</FormControl>
|
||||||
|
<FormMessage />
|
||||||
|
</FormItem>
|
||||||
|
</FormField>
|
||||||
|
</DE.Field>
|
||||||
|
</DE.Cell>
|
||||||
|
</template>
|
||||||
@@ -0,0 +1,69 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import type { FormErrors } from '~/types/error'
|
||||||
|
import Select from '~/components/pub/my-ui/form/select.vue'
|
||||||
|
import { cn } from '~/lib/utils'
|
||||||
|
|
||||||
|
import * as DE from '~/components/pub/my-ui/doc-entry'
|
||||||
|
|
||||||
|
const props = defineProps<{
|
||||||
|
fieldName: string
|
||||||
|
label: string
|
||||||
|
isDisabled?: boolean
|
||||||
|
isRequired?: boolean
|
||||||
|
placeholder?: string
|
||||||
|
errors?: FormErrors
|
||||||
|
class?: string
|
||||||
|
selectClass?: string
|
||||||
|
fieldGroupClass?: string
|
||||||
|
}>()
|
||||||
|
|
||||||
|
const { errors, class: containerClass, selectClass, fieldGroupClass } = props
|
||||||
|
|
||||||
|
const opts = [
|
||||||
|
{ label: 'PA', value: 'pa' },
|
||||||
|
{ label: 'Mikrobiologi', value: 'microbiology' },
|
||||||
|
{ label: 'Laborat', value: 'laboratory' },
|
||||||
|
{ label: 'Tidak Perlu', value: 'none' },
|
||||||
|
]
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<DE.Cell :class="cn('select-field-group', fieldGroupClass, containerClass)">
|
||||||
|
<DE.Label
|
||||||
|
label-for="fieldName"
|
||||||
|
:is-required="isRequired"
|
||||||
|
>
|
||||||
|
{{ label }}
|
||||||
|
</DE.Label>
|
||||||
|
<DE.Field
|
||||||
|
:id="fieldName"
|
||||||
|
:errors="errors"
|
||||||
|
:class="cn('select-field-wrapper')"
|
||||||
|
>
|
||||||
|
<FormField
|
||||||
|
v-slot="{ componentField }"
|
||||||
|
:name="fieldName"
|
||||||
|
>
|
||||||
|
<FormItem>
|
||||||
|
<FormControl>
|
||||||
|
<Select
|
||||||
|
:id="fieldName"
|
||||||
|
:is-disabled="isDisabled"
|
||||||
|
v-bind="componentField"
|
||||||
|
:items="opts"
|
||||||
|
:placeholder="placeholder"
|
||||||
|
:preserve-order="false"
|
||||||
|
:class="
|
||||||
|
cn(
|
||||||
|
'text-sm transition-all duration-200 focus:outline-none focus:ring-1 focus:ring-black focus:ring-offset-0',
|
||||||
|
selectClass,
|
||||||
|
)
|
||||||
|
"
|
||||||
|
/>
|
||||||
|
</FormControl>
|
||||||
|
<FormMessage />
|
||||||
|
</FormItem>
|
||||||
|
</FormField>
|
||||||
|
</DE.Field>
|
||||||
|
</DE.Cell>
|
||||||
|
</template>
|
||||||
@@ -0,0 +1,67 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import type { FormErrors } from '~/types/error'
|
||||||
|
import Select from '~/components/pub/my-ui/form/select.vue'
|
||||||
|
import { cn } from '~/lib/utils'
|
||||||
|
|
||||||
|
import * as DE from '~/components/pub/my-ui/doc-entry'
|
||||||
|
|
||||||
|
const props = defineProps<{
|
||||||
|
fieldName: string
|
||||||
|
label: string
|
||||||
|
isDisabled?: boolean
|
||||||
|
isRequired?: boolean
|
||||||
|
placeholder?: string
|
||||||
|
errors?: FormErrors
|
||||||
|
class?: string
|
||||||
|
selectClass?: string
|
||||||
|
fieldGroupClass?: string
|
||||||
|
}>()
|
||||||
|
|
||||||
|
const { errors, class: containerClass, selectClass, fieldGroupClass } = props
|
||||||
|
|
||||||
|
const opts = [
|
||||||
|
{ label: '1 (Satu)', value: 'first' },
|
||||||
|
{ label: 'Ulangan', value: 'retry' },
|
||||||
|
]
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<DE.Cell :class="cn('select-field-group', fieldGroupClass, containerClass)">
|
||||||
|
<DE.Label
|
||||||
|
label-for="fieldName"
|
||||||
|
:is-required="isRequired"
|
||||||
|
>
|
||||||
|
{{ label }}
|
||||||
|
</DE.Label>
|
||||||
|
<DE.Field
|
||||||
|
:id="fieldName"
|
||||||
|
:errors="errors"
|
||||||
|
:class="cn('select-field-wrapper')"
|
||||||
|
>
|
||||||
|
<FormField
|
||||||
|
v-slot="{ componentField }"
|
||||||
|
:name="fieldName"
|
||||||
|
>
|
||||||
|
<FormItem>
|
||||||
|
<FormControl>
|
||||||
|
<Select
|
||||||
|
:id="fieldName"
|
||||||
|
:is-disabled="isDisabled"
|
||||||
|
v-bind="componentField"
|
||||||
|
:items="opts"
|
||||||
|
:placeholder="placeholder"
|
||||||
|
:preserve-order="false"
|
||||||
|
:class="
|
||||||
|
cn(
|
||||||
|
'text-sm transition-all duration-200 focus:outline-none focus:ring-1 focus:ring-black focus:ring-offset-0',
|
||||||
|
selectClass,
|
||||||
|
)
|
||||||
|
"
|
||||||
|
/>
|
||||||
|
</FormControl>
|
||||||
|
<FormMessage />
|
||||||
|
</FormItem>
|
||||||
|
</FormField>
|
||||||
|
</DE.Field>
|
||||||
|
</DE.Cell>
|
||||||
|
</template>
|
||||||
@@ -0,0 +1,69 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import type { FormErrors } from '~/types/error'
|
||||||
|
import Select from '~/components/pub/my-ui/form/select.vue'
|
||||||
|
import { cn } from '~/lib/utils'
|
||||||
|
|
||||||
|
import * as DE from '~/components/pub/my-ui/doc-entry'
|
||||||
|
|
||||||
|
const props = defineProps<{
|
||||||
|
fieldName: string
|
||||||
|
label: string
|
||||||
|
isDisabled?: boolean
|
||||||
|
isRequired?: boolean
|
||||||
|
placeholder?: string
|
||||||
|
errors?: FormErrors
|
||||||
|
class?: string
|
||||||
|
selectClass?: string
|
||||||
|
fieldGroupClass?: string
|
||||||
|
}>()
|
||||||
|
|
||||||
|
const { errors, class: containerClass, selectClass, fieldGroupClass } = props
|
||||||
|
|
||||||
|
const opts = [
|
||||||
|
{ label: 'Kecil', value: 'kecil' },
|
||||||
|
{ label: 'Sedang', value: 'sedang' },
|
||||||
|
{ label: 'Besar', value: 'besar' },
|
||||||
|
{ label: 'Khusus', value: 'khusus' },
|
||||||
|
]
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<DE.Cell :class="cn('select-field-group', fieldGroupClass, containerClass)">
|
||||||
|
<DE.Label
|
||||||
|
label-for="fieldName"
|
||||||
|
:is-required="isRequired"
|
||||||
|
>
|
||||||
|
{{ label }}
|
||||||
|
</DE.Label>
|
||||||
|
<DE.Field
|
||||||
|
:id="fieldName"
|
||||||
|
:errors="errors"
|
||||||
|
:class="cn('select-field-wrapper')"
|
||||||
|
>
|
||||||
|
<FormField
|
||||||
|
v-slot="{ componentField }"
|
||||||
|
:name="fieldName"
|
||||||
|
>
|
||||||
|
<FormItem>
|
||||||
|
<FormControl>
|
||||||
|
<Select
|
||||||
|
:id="fieldName"
|
||||||
|
:is-disabled="isDisabled"
|
||||||
|
v-bind="componentField"
|
||||||
|
:items="opts"
|
||||||
|
:placeholder="placeholder"
|
||||||
|
:preserve-order="false"
|
||||||
|
:class="
|
||||||
|
cn(
|
||||||
|
'text-sm transition-all duration-200 focus:outline-none focus:ring-1 focus:ring-black focus:ring-offset-0',
|
||||||
|
selectClass,
|
||||||
|
)
|
||||||
|
"
|
||||||
|
/>
|
||||||
|
</FormControl>
|
||||||
|
<FormMessage />
|
||||||
|
</FormItem>
|
||||||
|
</FormField>
|
||||||
|
</DE.Field>
|
||||||
|
</DE.Cell>
|
||||||
|
</template>
|
||||||
@@ -0,0 +1,88 @@
|
|||||||
|
import { defineAsyncComponent } from 'vue'
|
||||||
|
|
||||||
|
import { format } from 'date-fns'
|
||||||
|
import { id } from 'date-fns/locale'
|
||||||
|
|
||||||
|
import type { Config, RecComponent } from '~/components/pub/my-ui/data-table'
|
||||||
|
import type { ActionReportData } from '~/components/app/action-report/sample'
|
||||||
|
const action = defineAsyncComponent(() => import('~/components/pub/my-ui/data/dropdown-action-d.vue'))
|
||||||
|
|
||||||
|
export const config: Config = {
|
||||||
|
cols: [
|
||||||
|
{ width: 120 },
|
||||||
|
{ width: 120 },
|
||||||
|
{ width: 120 },
|
||||||
|
{ width: 120 },
|
||||||
|
{ width: 120 },
|
||||||
|
{ width: 120 },
|
||||||
|
{ width: 120 },
|
||||||
|
{ width: 50 },
|
||||||
|
],
|
||||||
|
|
||||||
|
headers: [
|
||||||
|
[
|
||||||
|
{ label: 'TANGGAL LAPORAN' },
|
||||||
|
{ label: 'DPJP' },
|
||||||
|
{ label: 'OPERATOR' },
|
||||||
|
{ label: 'TANGGAL PEMBEDAHAN' },
|
||||||
|
{ label: 'JENIS OPERASI' },
|
||||||
|
{ label: 'KODE BILLING' },
|
||||||
|
{ label: 'SISTEM OPERASI' },
|
||||||
|
{ label: 'AKSI' },
|
||||||
|
],
|
||||||
|
],
|
||||||
|
|
||||||
|
keys: ['reportAt', 'dpjp', 'operator', 'operationAt', 'operationType', 'billing', 'system', 'action'],
|
||||||
|
|
||||||
|
delKeyNames: [
|
||||||
|
{ key: 'code', label: 'Kode' },
|
||||||
|
{ key: 'name', label: 'Nama' },
|
||||||
|
],
|
||||||
|
|
||||||
|
parses: {
|
||||||
|
reportAt: (rec: unknown): unknown => {
|
||||||
|
const attr = (rec as ActionReportData).reportAt
|
||||||
|
const result = format(new Date(attr), 'd MMMM yyyy, HH:mm', { locale: id })
|
||||||
|
|
||||||
|
return result
|
||||||
|
},
|
||||||
|
operationAt: (rec: unknown): unknown => {
|
||||||
|
const attr = (rec as ActionReportData).operationAt
|
||||||
|
const result = format(new Date(attr), 'd MMMM yyyy', { locale: id })
|
||||||
|
|
||||||
|
return result
|
||||||
|
},
|
||||||
|
system: (rec: unknown): unknown => {
|
||||||
|
return 'Cito'
|
||||||
|
},
|
||||||
|
operator: (rec: unknown): unknown => {
|
||||||
|
return 'dr. Dewi Arum Sawitri, Sp.An'
|
||||||
|
},
|
||||||
|
billing: (rec: unknown): unknown => {
|
||||||
|
return 'General'
|
||||||
|
},
|
||||||
|
operationType: (rec: unknown): unknown => {
|
||||||
|
return 'Besar'
|
||||||
|
},
|
||||||
|
dpjp: (rec: unknown): unknown => {
|
||||||
|
return 'dr. Irwansyah Kurniawan Sp.Bo'
|
||||||
|
},
|
||||||
|
parent: (rec: unknown): unknown => {
|
||||||
|
const recX = rec as any
|
||||||
|
return recX.parent?.name || '-'
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
components: {
|
||||||
|
action(rec, idx) {
|
||||||
|
const res: RecComponent = {
|
||||||
|
idx,
|
||||||
|
rec: rec as object,
|
||||||
|
component: action,
|
||||||
|
}
|
||||||
|
return res
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
htmls: {},
|
||||||
|
}
|
||||||
@@ -0,0 +1,39 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
// Components
|
||||||
|
import PaginationView from '~/components/pub/my-ui/pagination/pagination-view.vue'
|
||||||
|
|
||||||
|
// Types
|
||||||
|
import type { PaginationMeta } from '~/components/pub/my-ui/pagination/pagination.type'
|
||||||
|
|
||||||
|
// Configs
|
||||||
|
import { config } from './list.cfg'
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
data: any[]
|
||||||
|
paginationMeta: PaginationMeta
|
||||||
|
}
|
||||||
|
|
||||||
|
defineProps<Props>()
|
||||||
|
|
||||||
|
const emit = defineEmits<{
|
||||||
|
pageChange: [page: number]
|
||||||
|
}>()
|
||||||
|
|
||||||
|
function handlePageChange(page: number) {
|
||||||
|
emit('pageChange', page)
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="space-y-4">
|
||||||
|
<PubMyUiDataTable
|
||||||
|
v-bind="config"
|
||||||
|
:rows="data"
|
||||||
|
:skeleton-size="paginationMeta?.pageSize"
|
||||||
|
/>
|
||||||
|
<PaginationView
|
||||||
|
:pagination-meta="paginationMeta"
|
||||||
|
@page-change="handlePageChange"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
@@ -0,0 +1,89 @@
|
|||||||
|
import { defineAsyncComponent } from 'vue'
|
||||||
|
|
||||||
|
import { format } from 'date-fns'
|
||||||
|
import { id } from 'date-fns/locale'
|
||||||
|
|
||||||
|
import type { Config, RecComponent } from '~/components/pub/my-ui/data-table'
|
||||||
|
import type { ActionReportData } from '~/components/app/action-report/sample'
|
||||||
|
const action = defineAsyncComponent(() => import('~/components/pub/my-ui/data/dropdown-action-dud.vue'))
|
||||||
|
|
||||||
|
export const config: Config = {
|
||||||
|
cols: [
|
||||||
|
{ width: 120 },
|
||||||
|
{ width: 120 },
|
||||||
|
{ width: 120 },
|
||||||
|
{ width: 120 },
|
||||||
|
{ width: 120 },
|
||||||
|
{ width: 120 },
|
||||||
|
{ width: 120 },
|
||||||
|
{ width: 50 },
|
||||||
|
],
|
||||||
|
|
||||||
|
headers: [
|
||||||
|
[
|
||||||
|
{ label: 'TANGGAL LAPORAN' },
|
||||||
|
{ label: 'DPJP' },
|
||||||
|
{ label: 'OPERATOR' },
|
||||||
|
{ label: 'TANGGAL PEMBEDAHAN' },
|
||||||
|
{ label: 'JENIS OPERASI' },
|
||||||
|
{ label: 'KODE BILLING' },
|
||||||
|
{ label: 'SISTEM OPERASI' },
|
||||||
|
{ label: 'AKSI' },
|
||||||
|
],
|
||||||
|
],
|
||||||
|
|
||||||
|
keys: ['reportAt', 'dpjp', 'operator', 'operationAt', 'operationType', 'billing', 'system', 'action'],
|
||||||
|
|
||||||
|
delKeyNames: [
|
||||||
|
{ key: 'id', label: 'ID' },
|
||||||
|
{ key: 'dokter', label: 'Dokter' },
|
||||||
|
{ key: 'reportAt', label: 'Tanggal Laporan' },
|
||||||
|
],
|
||||||
|
|
||||||
|
parses: {
|
||||||
|
reportAt: (rec: unknown): unknown => {
|
||||||
|
const attr = (rec as ActionReportData).reportAt
|
||||||
|
const result = format(new Date(attr), 'd MMMM yyyy, HH:mm', { locale: id })
|
||||||
|
|
||||||
|
return result
|
||||||
|
},
|
||||||
|
operationAt: (rec: unknown): unknown => {
|
||||||
|
const attr = (rec as ActionReportData).operationAt
|
||||||
|
const result = format(new Date(attr), 'd MMMM yyyy', { locale: id })
|
||||||
|
|
||||||
|
return result
|
||||||
|
},
|
||||||
|
system: (rec: unknown): unknown => {
|
||||||
|
return 'Cito'
|
||||||
|
},
|
||||||
|
operator: (rec: unknown): unknown => {
|
||||||
|
return 'dr. Dewi Arum Sawitri, Sp.An'
|
||||||
|
},
|
||||||
|
billing: (rec: unknown): unknown => {
|
||||||
|
return 'General'
|
||||||
|
},
|
||||||
|
operationType: (rec: unknown): unknown => {
|
||||||
|
return 'Besar'
|
||||||
|
},
|
||||||
|
dpjp: (rec: unknown): unknown => {
|
||||||
|
return 'dr. Irwansyah Kurniawan Sp.Bo'
|
||||||
|
},
|
||||||
|
parent: (rec: unknown): unknown => {
|
||||||
|
const recX = rec as any
|
||||||
|
return recX.parent?.name || '-'
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
components: {
|
||||||
|
action(rec, idx) {
|
||||||
|
const res: RecComponent = {
|
||||||
|
idx,
|
||||||
|
rec: rec as object,
|
||||||
|
component: action,
|
||||||
|
}
|
||||||
|
return res
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
htmls: {},
|
||||||
|
}
|
||||||
@@ -0,0 +1,39 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
// Components
|
||||||
|
import PaginationView from '~/components/pub/my-ui/pagination/pagination-view.vue'
|
||||||
|
|
||||||
|
// Types
|
||||||
|
import type { PaginationMeta } from '~/components/pub/my-ui/pagination/pagination.type'
|
||||||
|
|
||||||
|
// Configs
|
||||||
|
import { config } from './list.cfg'
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
data: any[]
|
||||||
|
paginationMeta: PaginationMeta
|
||||||
|
}
|
||||||
|
|
||||||
|
defineProps<Props>()
|
||||||
|
|
||||||
|
const emit = defineEmits<{
|
||||||
|
pageChange: [page: number]
|
||||||
|
}>()
|
||||||
|
|
||||||
|
function handlePageChange(page: number) {
|
||||||
|
emit('pageChange', page)
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="space-y-4">
|
||||||
|
<PubMyUiDataTable
|
||||||
|
v-bind="config"
|
||||||
|
:rows="data"
|
||||||
|
:skeleton-size="paginationMeta?.pageSize"
|
||||||
|
/>
|
||||||
|
<PaginationView
|
||||||
|
:pagination-meta="paginationMeta"
|
||||||
|
@page-change="handlePageChange"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
@@ -0,0 +1,166 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import { format } from 'date-fns'
|
||||||
|
import { id } from 'date-fns/locale'
|
||||||
|
|
||||||
|
// type
|
||||||
|
import { type ProcedureSrc } from '~/models/procedure-src'
|
||||||
|
import { type ActionReportFormData } from '~/schemas/action-report.schema'
|
||||||
|
|
||||||
|
// componenets
|
||||||
|
import { Accordion, AccordionContent, AccordionItem, AccordionTrigger } from '~/components/pub/ui/accordion'
|
||||||
|
import * as DE from '~/components/pub/my-ui/doc-entry'
|
||||||
|
import DetailRow from '~/components/pub/my-ui/form/view/detail-row.vue'
|
||||||
|
import ArrangementProcedurePicker from '~/components/app/therapy-protocol/picker-dialog/arrangement-procedure/procedure-picker.vue'
|
||||||
|
|
||||||
|
// #region Props & Emits
|
||||||
|
const props = defineProps<{
|
||||||
|
data: ActionReportFormData
|
||||||
|
}>()
|
||||||
|
|
||||||
|
const emit = defineEmits<{
|
||||||
|
(e: 'back'): void
|
||||||
|
(e: 'edit'): void
|
||||||
|
}>()
|
||||||
|
|
||||||
|
// #endregion
|
||||||
|
|
||||||
|
// #region State & Computed
|
||||||
|
const { operatorTeam, procedures, operationExecution, bloodInput, implant, specimen, tissueNotes = [] } = props.data
|
||||||
|
|
||||||
|
const procedureSampleData = procedures as unknown as ProcedureSrc[]
|
||||||
|
// #region Lifecycle Hooks
|
||||||
|
// #endregion
|
||||||
|
|
||||||
|
// #region Functions
|
||||||
|
|
||||||
|
// #endregion region
|
||||||
|
// #region Utilities & event handlers
|
||||||
|
function onNavigate(type: string) {
|
||||||
|
if (type == 'back') emit('back')
|
||||||
|
if (type == 'edit') emit('edit')
|
||||||
|
}
|
||||||
|
// #endregion
|
||||||
|
|
||||||
|
// #region Watchers
|
||||||
|
// #endregion
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<DetailRow label="Tanggal Laporan">
|
||||||
|
{{ format(new Date(), 'd MMMM yyyy, HH:mm', { locale: id }) }}
|
||||||
|
</DetailRow>
|
||||||
|
|
||||||
|
<Accordion
|
||||||
|
type="multiple"
|
||||||
|
class="w-full"
|
||||||
|
collapsible
|
||||||
|
:default-value="['section-1', 'section-2', 'section-3']"
|
||||||
|
>
|
||||||
|
<AccordionItem value="section-1">
|
||||||
|
<AccordionTrigger>Tim Pelaksanaan Tindakan</AccordionTrigger>
|
||||||
|
<AccordionContent>
|
||||||
|
<DE.Block
|
||||||
|
:cell-flex="false"
|
||||||
|
:col-count="2"
|
||||||
|
>
|
||||||
|
<DE.Cell>
|
||||||
|
<DetailRow label="DPJP">dr. Marcell Galliard Sp.Gr</DetailRow>
|
||||||
|
<DetailRow label="Operator">Sumitro</DetailRow>
|
||||||
|
<DetailRow label="Asisten Operator">Alexis Lewis Carol</DetailRow>
|
||||||
|
<DetailRow label="Instrumentir">Mikel Arteta</DetailRow>
|
||||||
|
<DetailRow label="Tanggal Pembedahan">
|
||||||
|
{{ format(new Date(), 'd MMMM yyyy', { locale: id }) }}
|
||||||
|
</DetailRow>
|
||||||
|
<DetailRow label="Diagnosa Tindakan">{{ operatorTeam?.actionDiagnosis || '-' }}</DetailRow>
|
||||||
|
<DetailRow label="Perawat Pasca Bedah">Cak Armuji</DetailRow>
|
||||||
|
</DE.Cell>
|
||||||
|
</DE.Block>
|
||||||
|
</AccordionContent>
|
||||||
|
</AccordionItem>
|
||||||
|
|
||||||
|
<AccordionItem value="section-2">
|
||||||
|
<AccordionTrigger>Tindakan Operatif / Non Operatif Lain</AccordionTrigger>
|
||||||
|
<AccordionContent>
|
||||||
|
<DE.Block
|
||||||
|
:cell-flex="false"
|
||||||
|
:col-count="2"
|
||||||
|
>
|
||||||
|
<DE.Cell>
|
||||||
|
<ArrangementProcedurePicker
|
||||||
|
field-name="procedures"
|
||||||
|
title="List Prosedur"
|
||||||
|
sub-title="Pilih Prosedur"
|
||||||
|
:mode="'preview'"
|
||||||
|
:sample-items="procedureSampleData"
|
||||||
|
/>
|
||||||
|
</DE.Cell>
|
||||||
|
</DE.Block>
|
||||||
|
</AccordionContent>
|
||||||
|
</AccordionItem>
|
||||||
|
|
||||||
|
<AccordionItem value="section-3">
|
||||||
|
<AccordionTrigger>Data Pelaksanaan Tindakan</AccordionTrigger>
|
||||||
|
<AccordionContent>
|
||||||
|
<DE.Block
|
||||||
|
:cell-flex="false"
|
||||||
|
:col-count="2"
|
||||||
|
>
|
||||||
|
<DE.Cell>
|
||||||
|
<DetailRow label="Jenis Operasi">dr. Marcell Galliard Sp.Gr</DetailRow>
|
||||||
|
<DetailRow label="Kode Billing">GCASH1128190</DetailRow>
|
||||||
|
<DetailRow label="Sistem Operasi">Alexis Lewis Carol</DetailRow>
|
||||||
|
<DetailRow label="Operasi Mulai">
|
||||||
|
{{ format(new Date(), 'd MMMM yyyy, HH:mm', { locale: id }) }}
|
||||||
|
</DetailRow>
|
||||||
|
<DetailRow label="Operasi Selesai">
|
||||||
|
{{ format(new Date(), 'd MMMM yyyy, HH:mm', { locale: id }) }}
|
||||||
|
</DetailRow>
|
||||||
|
<DetailRow label="Lama Operasi">5 menit</DetailRow>
|
||||||
|
<DetailRow label="Pembiusan Mulai">
|
||||||
|
{{ format(new Date(), 'd MMMM yyyy, HH:mm', { locale: id }) }}
|
||||||
|
</DetailRow>
|
||||||
|
<DetailRow label="Pembiusan Selesai">
|
||||||
|
{{ format(new Date(), 'd MMMM yyyy, HH:mm', { locale: id }) }}
|
||||||
|
</DetailRow>
|
||||||
|
<DetailRow label="Lama Pembiusan">5 menit</DetailRow>
|
||||||
|
|
||||||
|
<DetailRow label="PRC">300 CC</DetailRow>
|
||||||
|
<DetailRow label="FPP">-</DetailRow>
|
||||||
|
<DetailRow label="WB">-</DetailRow>
|
||||||
|
<DetailRow label="TC">-</DetailRow>
|
||||||
|
<DetailRow label="Merk">-</DetailRow>
|
||||||
|
<DetailRow label="Nama Implant">-</DetailRow>
|
||||||
|
<DetailRow label="Sticker / Nomor Register Implant">-</DetailRow>
|
||||||
|
<DetailRow label="Nama Pendamping Implant">-</DetailRow>
|
||||||
|
</DE.Cell>
|
||||||
|
<DE.Cell>
|
||||||
|
<DetailRow label="Jenis Pembedahan">Bersih</DetailRow>
|
||||||
|
<DetailRow label="Operasi ke">1 (Satu)</DetailRow>
|
||||||
|
<DetailRow label="Keterangan Lahir">Lahir Hidup</DetailRow>
|
||||||
|
<DetailRow label="Ket. Tempat Lahir">RSSA</DetailRow>
|
||||||
|
<DetailRow label="Berat Badan">18 gram</DetailRow>
|
||||||
|
<DetailRow label="Ket. Saat Lahir">Normal dan sehat</DetailRow>
|
||||||
|
<DetailRow label="Uraian Operasi">-</DetailRow>
|
||||||
|
<DetailRow label="Jumlah Pendarahan">300 CC</DetailRow>
|
||||||
|
<DetailRow label="Specimen / Jaringan dikirim ke">PA</DetailRow>
|
||||||
|
<DetailRow label="Keterangan Jaringan">
|
||||||
|
<ul
|
||||||
|
class="list-disc space-y-1 pl-5 text-sm"
|
||||||
|
v-if="tissueNotes.length > 0"
|
||||||
|
v-for="item in tissueNotes"
|
||||||
|
>
|
||||||
|
<li>{{ item.note }}</li>
|
||||||
|
</ul>
|
||||||
|
<span v-else>-</span>
|
||||||
|
</DetailRow>
|
||||||
|
</DE.Cell>
|
||||||
|
</DE.Block>
|
||||||
|
</AccordionContent>
|
||||||
|
</AccordionItem>
|
||||||
|
</Accordion>
|
||||||
|
<div class="my-2 flex justify-end py-2">
|
||||||
|
<PubMyUiNavFooterBaEd @click="onNavigate" />
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped></style>
|
||||||
@@ -0,0 +1,54 @@
|
|||||||
|
import { addWeeks, formatISO } from 'date-fns'
|
||||||
|
|
||||||
|
export type ActionReportData = {
|
||||||
|
id: number
|
||||||
|
reportAt: string
|
||||||
|
operationAt: string
|
||||||
|
noRm: string
|
||||||
|
noBill: string
|
||||||
|
nama: string
|
||||||
|
jk: string
|
||||||
|
alamat: string
|
||||||
|
klinik: string
|
||||||
|
dokter: string
|
||||||
|
caraBayar: string
|
||||||
|
rujukan: string
|
||||||
|
ketRujukan: string
|
||||||
|
asal: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export const sampleRows: ActionReportData[] = [
|
||||||
|
{
|
||||||
|
id: 1,
|
||||||
|
reportAt: formatISO(addWeeks(new Date(), -1)),
|
||||||
|
operationAt: formatISO(addWeeks(new Date(), 1)),
|
||||||
|
noRm: 'RM23311224',
|
||||||
|
noBill: '-',
|
||||||
|
nama: 'Ahmad Baidowi',
|
||||||
|
jk: 'L',
|
||||||
|
alamat: 'Jl Jaksa Agung S. No. 9',
|
||||||
|
klinik: 'Penyakit dalam',
|
||||||
|
dokter: 'Dr. Andreas Sutaji',
|
||||||
|
caraBayar: 'JKN',
|
||||||
|
rujukan: 'Faskes BPJS',
|
||||||
|
ketRujukan: 'RUMAH SAKIT - RS Lawang Medika - Malang',
|
||||||
|
asal: 'Rawat Jalan Reguler',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 2,
|
||||||
|
reportAt: new Date().toISOString(),
|
||||||
|
operationAt: formatISO(addWeeks(new Date(), 2)),
|
||||||
|
noRm: 'RM23455667',
|
||||||
|
noBill: '-',
|
||||||
|
nama: 'Abraham Sulaiman',
|
||||||
|
jk: 'L',
|
||||||
|
alamat: 'Purwantoro, Blimbing',
|
||||||
|
klinik: 'Penyakit dalam',
|
||||||
|
dokter: 'Dr. Andreas Sutaji',
|
||||||
|
caraBayar: 'JKN',
|
||||||
|
rujukan: 'Faskes BPJS',
|
||||||
|
ketRujukan: 'RUMAH SAKIT - RS Lawang Medika - Malang',
|
||||||
|
asal: 'Rawat Jalan Reguler',
|
||||||
|
},
|
||||||
|
// tambahkan lebih banyak baris contoh jika perlu
|
||||||
|
]
|
||||||
+37
-31
@@ -1,13 +1,17 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
|
import { z } from 'zod'
|
||||||
|
import { FieldArray, useForm } from 'vee-validate'
|
||||||
import { toTypedSchema } from '@vee-validate/zod'
|
import { toTypedSchema } from '@vee-validate/zod'
|
||||||
import { FieldArray } from 'vee-validate'
|
|
||||||
import { Form } from '~/components/pub/ui/form'
|
// types
|
||||||
|
// import { type AssessmentEducationFormData, AssessmentEducationSchema, encode } from '~/schemas/assessment-education'
|
||||||
|
|
||||||
// componenets
|
// componenets
|
||||||
import * as DE from '~/components/pub/my-ui/doc-entry'
|
import * as DE from '~/components/pub/my-ui/doc-entry'
|
||||||
import Separator from '~/components/pub/ui/separator/Separator.vue'
|
import Separator from '~/components/pub/ui/separator/Separator.vue'
|
||||||
import { BaseSelect, CheckboxGeneral, CheckboxSpecial } from './fields'
|
import { BaseSelect, CheckboxGeneral, CheckboxSpecial } from './fields'
|
||||||
import { ButtonAction, TextAreaInput } from '~/components/pub/my-ui/form'
|
import { ButtonAction, TextAreaInput } from '~/components/pub/my-ui/form'
|
||||||
|
import ActionForm from '~/components/pub/my-ui/nav-footer/ba-dr-su.vue'
|
||||||
|
|
||||||
// constant
|
// constant
|
||||||
import {
|
import {
|
||||||
@@ -19,12 +23,13 @@ import {
|
|||||||
translatorSrcCode,
|
translatorSrcCode,
|
||||||
} from '~/lib/clinical.constants'
|
} from '~/lib/clinical.constants'
|
||||||
|
|
||||||
|
interface FormData {}
|
||||||
interface Props {
|
interface Props {
|
||||||
schema: any
|
noteLimit?: number
|
||||||
initialValues?: any
|
|
||||||
isLoading?: boolean
|
isLoading?: boolean
|
||||||
isReadonly?: boolean
|
isReadonly?: boolean
|
||||||
noteLimit?: number
|
mode: 'add' | 'edit' | 'view'
|
||||||
|
initialValues?: Partial<FormData>
|
||||||
}
|
}
|
||||||
|
|
||||||
const props = withDefaults(defineProps<Props>(), {
|
const props = withDefaults(defineProps<Props>(), {
|
||||||
@@ -33,37 +38,34 @@ const props = withDefaults(defineProps<Props>(), {
|
|||||||
noteLimit: 10,
|
noteLimit: 10,
|
||||||
})
|
})
|
||||||
const isDisabled = computed(() => props.isLoading || props.isReadonly)
|
const isDisabled = computed(() => props.isLoading || props.isReadonly)
|
||||||
|
// const formSchema = toTypedSchema(AssessmentEducationSchema)
|
||||||
const formSchema = toTypedSchema(props.schema)
|
const formSchema = toTypedSchema(z.object({}))
|
||||||
const formRef = ref()
|
const { errors, handleSubmit, values, meta, resetForm, setFieldValue, setValues, validate } = useForm<FormData>({
|
||||||
|
name: 'assessmentEducationForm',
|
||||||
defineExpose({
|
validationSchema: formSchema,
|
||||||
validate: () => formRef.value?.validate(),
|
initialValues: props.initialValues
|
||||||
resetForm: () => formRef.value?.resetForm(),
|
? props.initialValues
|
||||||
setValues: (values: any, shouldValidate = true) => formRef.value?.setValues(values, shouldValidate),
|
: {
|
||||||
values: computed(() => formRef.value?.values),
|
|
||||||
})
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<template>
|
|
||||||
<Form
|
|
||||||
ref="formRef"
|
|
||||||
as=""
|
|
||||||
keep-values
|
|
||||||
:validation-schema="formSchema"
|
|
||||||
:validate-on-mount="false"
|
|
||||||
validation-mode="onSubmit"
|
|
||||||
:initial-values="
|
|
||||||
initialValues || {
|
|
||||||
plans: [
|
plans: [
|
||||||
{
|
{
|
||||||
id: 1,
|
id: 1,
|
||||||
value: '',
|
value: '',
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
}
|
},
|
||||||
"
|
validateOnMount: false,
|
||||||
>
|
})
|
||||||
|
|
||||||
|
defineExpose({
|
||||||
|
validate,
|
||||||
|
resetForm,
|
||||||
|
setValues,
|
||||||
|
values,
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<form @submit.prevent="">
|
||||||
<p class="mb-2 text-sm font-semibold 2xl:mb-3 2xl:text-base">Kebutuhan Edukasi</p>
|
<p class="mb-2 text-sm font-semibold 2xl:mb-3 2xl:text-base">Kebutuhan Edukasi</p>
|
||||||
<DE.Block
|
<DE.Block
|
||||||
:col-count="4"
|
:col-count="4"
|
||||||
@@ -205,5 +207,9 @@ defineExpose({
|
|||||||
</div>
|
</div>
|
||||||
</FieldArray>
|
</FieldArray>
|
||||||
</DE.Block>
|
</DE.Block>
|
||||||
</Form>
|
<!-- todo -->
|
||||||
|
<div class="mt-4 flex justify-end">
|
||||||
|
<ActionForm @click="() => {}" />
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
</template>
|
</template>
|
||||||
@@ -0,0 +1,75 @@
|
|||||||
|
import { defineAsyncComponent } from 'vue'
|
||||||
|
|
||||||
|
import { format } from 'date-fns'
|
||||||
|
import { id } from 'date-fns/locale'
|
||||||
|
|
||||||
|
import type { Config, RecComponent } from '~/components/pub/my-ui/data-table'
|
||||||
|
import type { ActionReportData } from '~/components/app/action-report/sample'
|
||||||
|
const action = defineAsyncComponent(() => import('~/components/pub/my-ui/data/dropdown-action-dud.vue'))
|
||||||
|
|
||||||
|
export const config: Config = {
|
||||||
|
cols: [{ width: 120 }, { width: 120 }, { width: 120 }, { width: 120 }, { width: 120 }, { width: 50 }],
|
||||||
|
|
||||||
|
headers: [
|
||||||
|
[
|
||||||
|
{ label: 'TANGGAL' },
|
||||||
|
{ label: 'INFORMASI UMUM' },
|
||||||
|
{ label: 'EDUKASI KHUSUS' },
|
||||||
|
{ label: 'RENCANA EDUKASI' },
|
||||||
|
{ label: 'PELAKSANAAN' },
|
||||||
|
{ label: 'AKSI' },
|
||||||
|
],
|
||||||
|
],
|
||||||
|
|
||||||
|
keys: ['reportAt', 'dpjp', 'operator', 'operationAt', 'operationType', 'action'],
|
||||||
|
|
||||||
|
delKeyNames: [
|
||||||
|
{ key: 'id', label: 'ID' },
|
||||||
|
{ key: 'dokter', label: 'Dokter' },
|
||||||
|
{ key: 'reportAt', label: 'Tanggal Laporan' },
|
||||||
|
],
|
||||||
|
|
||||||
|
parses: {
|
||||||
|
reportAt: (rec: unknown): unknown => {
|
||||||
|
const attr = (rec as ActionReportData).reportAt
|
||||||
|
const result = format(new Date(attr), 'd MMMM yyyy, HH:mm', { locale: id })
|
||||||
|
|
||||||
|
return result
|
||||||
|
},
|
||||||
|
operationAt: (rec: unknown): unknown => {
|
||||||
|
return '1 Rencana Edukasi'
|
||||||
|
},
|
||||||
|
system: (rec: unknown): unknown => {
|
||||||
|
return 'Cito'
|
||||||
|
},
|
||||||
|
operator: (rec: unknown): unknown => {
|
||||||
|
return '2 Edukasi dipilih'
|
||||||
|
},
|
||||||
|
billing: (rec: unknown): unknown => {
|
||||||
|
return 'General'
|
||||||
|
},
|
||||||
|
operationType: (rec: unknown): unknown => {
|
||||||
|
return '-'
|
||||||
|
},
|
||||||
|
dpjp: (rec: unknown): unknown => {
|
||||||
|
return '3 Informasi Dipilih'
|
||||||
|
},
|
||||||
|
parent: (rec: unknown): unknown => {
|
||||||
|
const recX = rec as any
|
||||||
|
return recX.parent?.name || '-'
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
components: {
|
||||||
|
action(rec, idx) {
|
||||||
|
const res: RecComponent = {
|
||||||
|
idx,
|
||||||
|
rec: rec as object,
|
||||||
|
component: action,
|
||||||
|
}
|
||||||
|
return res
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
htmls: {},
|
||||||
|
}
|
||||||
@@ -0,0 +1,39 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
// Components
|
||||||
|
import PaginationView from '~/components/pub/my-ui/pagination/pagination-view.vue'
|
||||||
|
|
||||||
|
// Types
|
||||||
|
import type { PaginationMeta } from '~/components/pub/my-ui/pagination/pagination.type'
|
||||||
|
|
||||||
|
// Configs
|
||||||
|
import { config } from './list.cfg'
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
data: any[]
|
||||||
|
paginationMeta: PaginationMeta
|
||||||
|
}
|
||||||
|
|
||||||
|
defineProps<Props>()
|
||||||
|
|
||||||
|
const emit = defineEmits<{
|
||||||
|
pageChange: [page: number]
|
||||||
|
}>()
|
||||||
|
|
||||||
|
function handlePageChange(page: number) {
|
||||||
|
emit('pageChange', page)
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="space-y-4">
|
||||||
|
<PubMyUiDataTable
|
||||||
|
v-bind="config"
|
||||||
|
:rows="data"
|
||||||
|
:skeleton-size="paginationMeta?.pageSize"
|
||||||
|
/>
|
||||||
|
<PaginationView
|
||||||
|
:pagination-meta="paginationMeta"
|
||||||
|
@page-change="handlePageChange"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
@@ -0,0 +1,75 @@
|
|||||||
|
import { defineAsyncComponent } from 'vue'
|
||||||
|
|
||||||
|
import { format } from 'date-fns'
|
||||||
|
import { id } from 'date-fns/locale'
|
||||||
|
|
||||||
|
import type { Config, RecComponent } from '~/components/pub/my-ui/data-table'
|
||||||
|
import type { ActionReportData } from '~/components/app/action-report/sample'
|
||||||
|
const action = defineAsyncComponent(() => import('~/components/pub/my-ui/data/dropdown-action-dud.vue'))
|
||||||
|
|
||||||
|
export const config: Config = {
|
||||||
|
cols: [{ width: 120 }, { width: 120 }, { width: 120 }, { width: 120 }, { width: 120 }, { width: 50 }],
|
||||||
|
|
||||||
|
headers: [
|
||||||
|
[
|
||||||
|
{ label: 'TANGGAL' },
|
||||||
|
{ label: 'INFORMASI UMUM' },
|
||||||
|
{ label: 'EDUKASI KHUSUS' },
|
||||||
|
{ label: 'RENCANA EDUKASI' },
|
||||||
|
{ label: 'PELAKSANAAN' },
|
||||||
|
{ label: 'AKSI' },
|
||||||
|
],
|
||||||
|
],
|
||||||
|
|
||||||
|
keys: ['reportAt', 'dpjp', 'operator', 'operationAt', 'operationType', 'action'],
|
||||||
|
|
||||||
|
delKeyNames: [
|
||||||
|
{ key: 'id', label: 'ID' },
|
||||||
|
{ key: 'dokter', label: 'Dokter' },
|
||||||
|
{ key: 'reportAt', label: 'Tanggal Laporan' },
|
||||||
|
],
|
||||||
|
|
||||||
|
parses: {
|
||||||
|
reportAt: (rec: unknown): unknown => {
|
||||||
|
const attr = (rec as ActionReportData).reportAt
|
||||||
|
const result = format(new Date(attr), 'd MMMM yyyy, HH:mm', { locale: id })
|
||||||
|
|
||||||
|
return result
|
||||||
|
},
|
||||||
|
operationAt: (rec: unknown): unknown => {
|
||||||
|
return '1 Rencana Edukasi'
|
||||||
|
},
|
||||||
|
system: (rec: unknown): unknown => {
|
||||||
|
return 'Cito'
|
||||||
|
},
|
||||||
|
operator: (rec: unknown): unknown => {
|
||||||
|
return '2 Edukasi dipilih'
|
||||||
|
},
|
||||||
|
billing: (rec: unknown): unknown => {
|
||||||
|
return 'General'
|
||||||
|
},
|
||||||
|
operationType: (rec: unknown): unknown => {
|
||||||
|
return '-'
|
||||||
|
},
|
||||||
|
dpjp: (rec: unknown): unknown => {
|
||||||
|
return '3 Informasi Dipilih'
|
||||||
|
},
|
||||||
|
parent: (rec: unknown): unknown => {
|
||||||
|
const recX = rec as any
|
||||||
|
return recX.parent?.name || '-'
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
components: {
|
||||||
|
action(rec, idx) {
|
||||||
|
const res: RecComponent = {
|
||||||
|
idx,
|
||||||
|
rec: rec as object,
|
||||||
|
component: action,
|
||||||
|
}
|
||||||
|
return res
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
htmls: {},
|
||||||
|
}
|
||||||
@@ -0,0 +1,39 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
// Components
|
||||||
|
import PaginationView from '~/components/pub/my-ui/pagination/pagination-view.vue'
|
||||||
|
|
||||||
|
// Types
|
||||||
|
import type { PaginationMeta } from '~/components/pub/my-ui/pagination/pagination.type'
|
||||||
|
|
||||||
|
// Configs
|
||||||
|
import { config } from './list.cfg'
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
data: any[]
|
||||||
|
paginationMeta: PaginationMeta
|
||||||
|
}
|
||||||
|
|
||||||
|
defineProps<Props>()
|
||||||
|
|
||||||
|
const emit = defineEmits<{
|
||||||
|
pageChange: [page: number]
|
||||||
|
}>()
|
||||||
|
|
||||||
|
function handlePageChange(page: number) {
|
||||||
|
emit('pageChange', page)
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="space-y-4">
|
||||||
|
<PubMyUiDataTable
|
||||||
|
v-bind="config"
|
||||||
|
:rows="data"
|
||||||
|
:skeleton-size="paginationMeta?.pageSize"
|
||||||
|
/>
|
||||||
|
<PaginationView
|
||||||
|
:pagination-meta="paginationMeta"
|
||||||
|
@page-change="handlePageChange"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
@@ -0,0 +1,54 @@
|
|||||||
|
import { addWeeks, formatISO } from 'date-fns'
|
||||||
|
|
||||||
|
export type ActionReportData = {
|
||||||
|
id: number
|
||||||
|
reportAt: string
|
||||||
|
operationAt: string
|
||||||
|
noRm: string
|
||||||
|
noBill: string
|
||||||
|
nama: string
|
||||||
|
jk: string
|
||||||
|
alamat: string
|
||||||
|
klinik: string
|
||||||
|
dokter: string
|
||||||
|
caraBayar: string
|
||||||
|
rujukan: string
|
||||||
|
ketRujukan: string
|
||||||
|
asal: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export const sampleRows: ActionReportData[] = [
|
||||||
|
{
|
||||||
|
id: 1,
|
||||||
|
reportAt: formatISO(addWeeks(new Date(), -1)),
|
||||||
|
operationAt: formatISO(addWeeks(new Date(), 1)),
|
||||||
|
noRm: 'RM23311224',
|
||||||
|
noBill: '-',
|
||||||
|
nama: 'Ahmad Baidowi',
|
||||||
|
jk: 'L',
|
||||||
|
alamat: 'Jl Jaksa Agung S. No. 9',
|
||||||
|
klinik: 'Penyakit dalam',
|
||||||
|
dokter: 'Dr. Andreas Sutaji',
|
||||||
|
caraBayar: 'JKN',
|
||||||
|
rujukan: 'Faskes BPJS',
|
||||||
|
ketRujukan: 'RUMAH SAKIT - RS Lawang Medika - Malang',
|
||||||
|
asal: 'Rawat Jalan Reguler',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 2,
|
||||||
|
reportAt: new Date().toISOString(),
|
||||||
|
operationAt: formatISO(addWeeks(new Date(), 2)),
|
||||||
|
noRm: 'RM23455667',
|
||||||
|
noBill: '-',
|
||||||
|
nama: 'Abraham Sulaiman',
|
||||||
|
jk: 'L',
|
||||||
|
alamat: 'Purwantoro, Blimbing',
|
||||||
|
klinik: 'Penyakit dalam',
|
||||||
|
dokter: 'Dr. Andreas Sutaji',
|
||||||
|
caraBayar: 'JKN',
|
||||||
|
rujukan: 'Faskes BPJS',
|
||||||
|
ketRujukan: 'RUMAH SAKIT - RS Lawang Medika - Malang',
|
||||||
|
asal: 'Rawat Jalan Reguler',
|
||||||
|
},
|
||||||
|
// tambahkan lebih banyak baris contoh jika perlu
|
||||||
|
]
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
export { default as SelectDoctor } from './select-doctor.vue'
|
||||||
@@ -0,0 +1,72 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import { cn } from '~/lib/utils'
|
||||||
|
|
||||||
|
// type
|
||||||
|
import type { Doctor } from '~/models/doctor'
|
||||||
|
import { type Person, parseName } from '~/models/person'
|
||||||
|
|
||||||
|
// componenets
|
||||||
|
import * as DE from '~/components/pub/my-ui/doc-entry'
|
||||||
|
import Combobox from '~/components/pub/my-ui/combobox/combobox.vue'
|
||||||
|
|
||||||
|
const props = defineProps<{
|
||||||
|
fieldName: string
|
||||||
|
label: string
|
||||||
|
placeholder: string
|
||||||
|
doctors?: Doctor[]
|
||||||
|
class?: string
|
||||||
|
selectClass?: string
|
||||||
|
fieldGroupClass?: string
|
||||||
|
labelClass?: string
|
||||||
|
isRequired?: boolean
|
||||||
|
isDisabled?: boolean
|
||||||
|
colSpan?: number
|
||||||
|
}>()
|
||||||
|
|
||||||
|
const { class: containerClass, labelClass, colSpan = 1, doctors = [] } = props
|
||||||
|
|
||||||
|
const opts = computed(() => {
|
||||||
|
return doctors.map((doc) => ({
|
||||||
|
value: doc.id,
|
||||||
|
label: parseName(doc.employee.person as Person),
|
||||||
|
}))
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<DE.Cell
|
||||||
|
:col-span="colSpan"
|
||||||
|
:class="cn('select-field-group', fieldGroupClass, containerClass)"
|
||||||
|
>
|
||||||
|
<DE.Label
|
||||||
|
:label-for="fieldName"
|
||||||
|
:is-required="isRequired"
|
||||||
|
>
|
||||||
|
{{ label }}
|
||||||
|
</DE.Label>
|
||||||
|
<DE.Field
|
||||||
|
:id="fieldName"
|
||||||
|
:class="cn('select-field-wrapper')"
|
||||||
|
>
|
||||||
|
<FormField
|
||||||
|
v-slot="{ componentField }"
|
||||||
|
:name="fieldName"
|
||||||
|
>
|
||||||
|
<FormItem>
|
||||||
|
<FormControl>
|
||||||
|
<Combobox
|
||||||
|
:id="fieldName"
|
||||||
|
v-bind="componentField"
|
||||||
|
:items="opts"
|
||||||
|
:placeholder="placeholder"
|
||||||
|
:is-disabled="isDisabled"
|
||||||
|
search-placeholder="Cari dokter..."
|
||||||
|
empty-message="Dokter tidak ditemukan"
|
||||||
|
/>
|
||||||
|
</FormControl>
|
||||||
|
<FormMessage />
|
||||||
|
</FormItem>
|
||||||
|
</FormField>
|
||||||
|
</DE.Field>
|
||||||
|
</DE.Cell>
|
||||||
|
</template>
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import List from './list.vue'
|
||||||
|
import Form from './form.vue'
|
||||||
|
import View from './view.vue'
|
||||||
|
|
||||||
|
// Models
|
||||||
|
import type { Encounter } from '~/models/encounter'
|
||||||
|
|
||||||
|
// Props
|
||||||
|
interface Props {
|
||||||
|
encounter: Encounter
|
||||||
|
}
|
||||||
|
|
||||||
|
const props = defineProps<Props>()
|
||||||
|
|
||||||
|
const { mode, goToEntry, goToView } = useQueryCRUDMode('mode')
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<List
|
||||||
|
v-if="mode === 'list'"
|
||||||
|
:encounter="props.encounter"
|
||||||
|
@add="goToEntry"
|
||||||
|
@edit="goToEntry({ fromView: false })"
|
||||||
|
@view="goToView"
|
||||||
|
/>
|
||||||
|
<View
|
||||||
|
v-else-if="mode === 'view'"
|
||||||
|
:encounter="props.encounter"
|
||||||
|
/>
|
||||||
|
<Form v-else />
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
@@ -0,0 +1,82 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import mockData from './sample'
|
||||||
|
|
||||||
|
// type
|
||||||
|
import { genDoctor, type Doctor } from '~/models/doctor'
|
||||||
|
import type { ActionReportFormData } from '~/schemas/action-report.schema'
|
||||||
|
|
||||||
|
// components
|
||||||
|
import { toast } from '~/components/pub/ui/toast'
|
||||||
|
import AppActionReportEntry from '~/components/app/action-report/entry-form.vue'
|
||||||
|
import ArrangementProcedurePicker from '~/components/app/therapy-protocol/picker-dialog/arrangement-procedure/procedure-picker.vue'
|
||||||
|
|
||||||
|
// states
|
||||||
|
const route = useRoute()
|
||||||
|
const { mode, goBack } = useQueryCRUDMode('mode')
|
||||||
|
const { recordId } = useQueryCRUDRecordId('record-id')
|
||||||
|
const reportData = ref<ActionReportFormData>({} as unknown as ActionReportFormData)
|
||||||
|
const doctors = ref<Doctor[]>([])
|
||||||
|
const isLoading = ref<boolean>(false)
|
||||||
|
|
||||||
|
// TODO: dummy data
|
||||||
|
;(() => {
|
||||||
|
doctors.value = [genDoctor()]
|
||||||
|
})()
|
||||||
|
|
||||||
|
const entryMode = ref<'add' | 'edit' | 'view'>('add')
|
||||||
|
const isDataReady = ref(false)
|
||||||
|
|
||||||
|
onMounted(async () => {
|
||||||
|
if (mode.value === 'entry' && recordId.value) {
|
||||||
|
entryMode.value = 'edit'
|
||||||
|
await loadEntryForEdit(+recordId.value)
|
||||||
|
} else {
|
||||||
|
// Untuk mode 'add', langsung set ready
|
||||||
|
isDataReady.value = true
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
// TODO: map data
|
||||||
|
async function loadEntryForEdit(id: number | string) {
|
||||||
|
isLoading.value = true
|
||||||
|
const result = mockData
|
||||||
|
reportData.value = result as ActionReportFormData
|
||||||
|
isLoading.value = false
|
||||||
|
isDataReady.value = true
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<AppActionReportEntry
|
||||||
|
v-if="isDataReady"
|
||||||
|
:isLoading="isLoading"
|
||||||
|
:mode="entryMode"
|
||||||
|
@submit="(val) => console.log(val)"
|
||||||
|
@back="goBack"
|
||||||
|
@error="
|
||||||
|
(err: Error) => {
|
||||||
|
toast({
|
||||||
|
title: 'Terjadi Kesalahan',
|
||||||
|
description: err.message,
|
||||||
|
variant: 'destructive',
|
||||||
|
})
|
||||||
|
}
|
||||||
|
"
|
||||||
|
:doctors="doctors"
|
||||||
|
:initialValues="reportData"
|
||||||
|
>
|
||||||
|
<template #procedures>
|
||||||
|
<ArrangementProcedurePicker
|
||||||
|
field-name="procedures"
|
||||||
|
title="Tindakan Operatif/Non-Operatif Lain"
|
||||||
|
sub-title="Pilih Prosedur"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
</AppActionReportEntry>
|
||||||
|
<div
|
||||||
|
v-else
|
||||||
|
class="flex items-center justify-center p-8"
|
||||||
|
>
|
||||||
|
<p class="text-muted-foreground">Memuat data...</p>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
@@ -0,0 +1,276 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
// Components
|
||||||
|
import Dialog from '~/components/pub/my-ui/modal/dialog.vue'
|
||||||
|
import AppActionReportList from '~/components/app/action-report/list.vue'
|
||||||
|
import AppActionReportListHistory from '~/components/app/action-report/list-history.vue'
|
||||||
|
import RecordConfirmation from '~/components/pub/my-ui/confirmation/record-confirmation.vue'
|
||||||
|
import { ButtonAction } from '~/components/pub/my-ui/form'
|
||||||
|
|
||||||
|
// config
|
||||||
|
import { config } from '~/components/app/action-report/list.cfg'
|
||||||
|
|
||||||
|
// types
|
||||||
|
import { ActionEvents } from '~/components/pub/my-ui/data/types'
|
||||||
|
import type { Encounter } from '~/models/encounter'
|
||||||
|
|
||||||
|
// Samples
|
||||||
|
import { sampleRows, type ActionReportData } from '~/components/app/action-report/sample'
|
||||||
|
import sampleReport from './sample'
|
||||||
|
|
||||||
|
// helpers
|
||||||
|
import { toast } from '~/components/pub/ui/toast'
|
||||||
|
|
||||||
|
// Props
|
||||||
|
interface Props {
|
||||||
|
encounter: Encounter
|
||||||
|
}
|
||||||
|
const props = defineProps<Props>()
|
||||||
|
const emits = defineEmits<{
|
||||||
|
(e: 'add'): void
|
||||||
|
(e: 'edit', id: number | string): void
|
||||||
|
(e: 'view', id: number | string): void
|
||||||
|
}>()
|
||||||
|
|
||||||
|
// states
|
||||||
|
const router = useRouter()
|
||||||
|
const route = useRoute()
|
||||||
|
const { goToEntry, backToList } = useQueryCRUDMode('mode')
|
||||||
|
const title = ref('')
|
||||||
|
const search = ref('')
|
||||||
|
const dateFrom = ref('')
|
||||||
|
const dateTo = ref('')
|
||||||
|
const isDialogOpen = ref<boolean>(false)
|
||||||
|
const isLoading = ref<boolean>(false)
|
||||||
|
|
||||||
|
// #region mock
|
||||||
|
// Handlers
|
||||||
|
import {
|
||||||
|
recId,
|
||||||
|
recAction,
|
||||||
|
recItem,
|
||||||
|
isReadonly,
|
||||||
|
isProcessing,
|
||||||
|
isFormEntryDialogOpen,
|
||||||
|
isRecordConfirmationOpen,
|
||||||
|
onResetState,
|
||||||
|
handleActionSave,
|
||||||
|
handleActionEdit,
|
||||||
|
handleActionRemove,
|
||||||
|
handleCancelForm,
|
||||||
|
} from '~/handlers/consultation.handler'
|
||||||
|
// #endregion
|
||||||
|
|
||||||
|
// filter + pencarian sederhana (client-side)
|
||||||
|
const filtered = computed(() => {
|
||||||
|
const q = search.value.trim().toLowerCase()
|
||||||
|
return sampleRows.filter((r: ActionReportData) => {
|
||||||
|
if (q) {
|
||||||
|
return r.nama.toLowerCase().includes(q) || r.noRm.toLowerCase().includes(q) || r.dokter.toLowerCase().includes(q)
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
const goEdit = (id: number | string) => {
|
||||||
|
router.replace({
|
||||||
|
path: route.path,
|
||||||
|
query: {
|
||||||
|
...route.query,
|
||||||
|
mode: 'entry',
|
||||||
|
'record-id': id,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const goView = (id: number | string) => {
|
||||||
|
router.replace({
|
||||||
|
path: route.path,
|
||||||
|
query: {
|
||||||
|
...route.query,
|
||||||
|
mode: 'view',
|
||||||
|
'record-id': id,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
provide('rec_id', recId)
|
||||||
|
provide('rec_action', recAction)
|
||||||
|
provide('rec_item', recItem)
|
||||||
|
provide('table_data_loader', isLoading)
|
||||||
|
|
||||||
|
async function onGetDetail(id: number | string) {
|
||||||
|
isLoading.value = true
|
||||||
|
const res = sampleReport
|
||||||
|
recItem.value = res
|
||||||
|
console.log(res)
|
||||||
|
isLoading.value = false
|
||||||
|
}
|
||||||
|
|
||||||
|
// #region watcher
|
||||||
|
watch([recId, recAction], (newVal) => {
|
||||||
|
const [id, action] = newVal
|
||||||
|
|
||||||
|
// Guard: jangan proses jika id = 0 atau action kosong
|
||||||
|
if (!id || !action) return
|
||||||
|
|
||||||
|
switch (action) {
|
||||||
|
case ActionEvents.showDetail:
|
||||||
|
// onGetDetail(recId.value)
|
||||||
|
goView(id)
|
||||||
|
title.value = 'Detail Konsultasi'
|
||||||
|
break
|
||||||
|
case ActionEvents.showEdit:
|
||||||
|
goEdit(id)
|
||||||
|
title.value = 'Edit Konsultasi'
|
||||||
|
break
|
||||||
|
case ActionEvents.showConfirmDelete:
|
||||||
|
isRecordConfirmationOpen.value = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reset KEDUANYA menggunakan nextTick agar tidak trigger watcher lagi
|
||||||
|
nextTick(() => {
|
||||||
|
recId.value = 0
|
||||||
|
recAction.value = ''
|
||||||
|
})
|
||||||
|
})
|
||||||
|
// #endregion
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="mx-auto max-w-full">
|
||||||
|
<div class="border-b p-6">
|
||||||
|
<h1 class="text-2xl font-semibold">Laporan Tindakan</h1>
|
||||||
|
<p class="mt-1 text-sm text-gray-500">Infomasi laporan tindakan pasien</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="flex flex-wrap items-center gap-3 border-b p-4">
|
||||||
|
<div class="flex items-center gap-2">
|
||||||
|
<input
|
||||||
|
v-model="search"
|
||||||
|
placeholder="Cari Nama / No.RM"
|
||||||
|
class="w-64 rounded border px-3 py-2"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="flex items-center gap-2">
|
||||||
|
<input
|
||||||
|
v-model="dateFrom"
|
||||||
|
type="date"
|
||||||
|
class="rounded border px-3 py-2"
|
||||||
|
/>
|
||||||
|
<span class="text-sm text-gray-500">-</span>
|
||||||
|
<input
|
||||||
|
v-model="dateTo"
|
||||||
|
type="date"
|
||||||
|
class="rounded border px-3 py-2"
|
||||||
|
/>
|
||||||
|
<ButtonAction
|
||||||
|
preset="custom"
|
||||||
|
title="Filter List Laporan Tindakan"
|
||||||
|
label="Filter"
|
||||||
|
icon="i-lucide-filter"
|
||||||
|
@click="
|
||||||
|
() => {
|
||||||
|
isDialogOpen = true
|
||||||
|
}
|
||||||
|
"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="ml-auto flex items-center gap-2">
|
||||||
|
<ButtonAction
|
||||||
|
preset="custom"
|
||||||
|
title="Riwayat Laporan Tindakan"
|
||||||
|
icon="i-lucide-history"
|
||||||
|
label="Riwayat Laporan Tindakan"
|
||||||
|
@click="
|
||||||
|
() => {
|
||||||
|
isDialogOpen = true
|
||||||
|
}
|
||||||
|
"
|
||||||
|
/>
|
||||||
|
<ButtonAction
|
||||||
|
preset="add"
|
||||||
|
title="Tambah Data Laporan Tindakan"
|
||||||
|
icon="i-lucide-plus"
|
||||||
|
label="Tambah Data"
|
||||||
|
@click="
|
||||||
|
() => {
|
||||||
|
goToEntry()
|
||||||
|
}
|
||||||
|
"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="overflow-x-auto p-4">
|
||||||
|
<AppActionReportList
|
||||||
|
:data="filtered"
|
||||||
|
:pagination-meta="{
|
||||||
|
recordCount: 2,
|
||||||
|
page: 1,
|
||||||
|
pageSize: 10,
|
||||||
|
totalPage: 1,
|
||||||
|
hasPrev: false,
|
||||||
|
hasNext: false,
|
||||||
|
}"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<Dialog
|
||||||
|
v-model:open="isDialogOpen"
|
||||||
|
title="Arsip Riwayat Laporan Tindakan"
|
||||||
|
size="2xl"
|
||||||
|
prevent-outside
|
||||||
|
@update:open="
|
||||||
|
(value: any) => {
|
||||||
|
isDialogOpen = value
|
||||||
|
}
|
||||||
|
"
|
||||||
|
>
|
||||||
|
<AppActionReportListHistory
|
||||||
|
:data="filtered"
|
||||||
|
:pagination-meta="{
|
||||||
|
recordCount: 2,
|
||||||
|
page: 1,
|
||||||
|
pageSize: 10,
|
||||||
|
totalPage: 1,
|
||||||
|
hasPrev: false,
|
||||||
|
hasNext: false,
|
||||||
|
}"
|
||||||
|
/>
|
||||||
|
</Dialog>
|
||||||
|
|
||||||
|
<RecordConfirmation
|
||||||
|
v-model:open="isRecordConfirmationOpen"
|
||||||
|
action="delete"
|
||||||
|
:record="recItem"
|
||||||
|
@confirm="
|
||||||
|
() =>
|
||||||
|
handleActionRemove(
|
||||||
|
recItem.id,
|
||||||
|
() => {
|
||||||
|
router.go(0)
|
||||||
|
},
|
||||||
|
toast,
|
||||||
|
)
|
||||||
|
"
|
||||||
|
@cancel=""
|
||||||
|
>
|
||||||
|
<template #default="{ record }">
|
||||||
|
{{ console.log(JSON.stringify(record)) }}
|
||||||
|
<div class="space-y-1 text-sm">
|
||||||
|
<p
|
||||||
|
v-for="field in config.delKeyNames"
|
||||||
|
:key="field.key"
|
||||||
|
:v-if="record?.[field.key]"
|
||||||
|
>
|
||||||
|
<span class="font-semibold">{{ field.label }}:</span>
|
||||||
|
{{ record[field.key] }}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</RecordConfirmation>
|
||||||
|
</template>
|
||||||
@@ -0,0 +1,68 @@
|
|||||||
|
export default {
|
||||||
|
operatorTeam: {
|
||||||
|
dpjpId: -1,
|
||||||
|
operatorName: 'Julian Alvarez',
|
||||||
|
assistantOperatorName: 'Arda Guller',
|
||||||
|
instrumentNurseName: 'Kenan Yildiz',
|
||||||
|
surgeryDate: '2025-11-13T14:29:00',
|
||||||
|
actionDiagnosis: 'Sprei gratisnya mana',
|
||||||
|
},
|
||||||
|
procedures: [
|
||||||
|
{
|
||||||
|
id: -1,
|
||||||
|
name: 'Ndase mumet',
|
||||||
|
code: 'CX1',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
operationExecution: {
|
||||||
|
surgeryType: 'khusus',
|
||||||
|
billingCode: 'local',
|
||||||
|
operationSystem: 'cito',
|
||||||
|
surgeryCleanType: 'kotor',
|
||||||
|
surgeryNumber: 'retry',
|
||||||
|
birthPlaceNote: 'out3',
|
||||||
|
personWeight: 100,
|
||||||
|
operationDescription: 'asdsadsa1',
|
||||||
|
birthRemark: 'lahir_hidup',
|
||||||
|
|
||||||
|
operationStartAt: '2025-11-13T14:29:00',
|
||||||
|
operationEndAt: '2025-11-13T17:29:00',
|
||||||
|
|
||||||
|
anesthesiaStartAt: '2025-11-13T11:29:00',
|
||||||
|
anesthesiaEndAt: '2025-11-13T18:29:00',
|
||||||
|
},
|
||||||
|
bloodInput: {
|
||||||
|
type: 'tc',
|
||||||
|
amount: {
|
||||||
|
prc: null,
|
||||||
|
wb: null,
|
||||||
|
ffp: null,
|
||||||
|
tc: 3243324,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
implant: {
|
||||||
|
brand: 'Samsung',
|
||||||
|
name: 'S.Komedi',
|
||||||
|
companionName: 'When ya',
|
||||||
|
},
|
||||||
|
specimen: {
|
||||||
|
destination: 'pa',
|
||||||
|
},
|
||||||
|
tissueNotes: [
|
||||||
|
{
|
||||||
|
note: 'Anjai',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
note: 'Ciee Kaget',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
note: 'Baper',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
note: 'Saltink weeh',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
note: 'Kaburrr',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}
|
||||||
@@ -0,0 +1,67 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import mockData from './sample'
|
||||||
|
|
||||||
|
// types
|
||||||
|
import { type ActionReportFormData } from '~/schemas/action-report.schema'
|
||||||
|
import { type Encounter } from '~/models/encounter'
|
||||||
|
|
||||||
|
// Components
|
||||||
|
import AppActionReportPreview from '~/components/app/action-report/preview.vue'
|
||||||
|
import type { HeaderPrep } from '~/components/pub/my-ui/data/types'
|
||||||
|
|
||||||
|
// #region Props & Emits
|
||||||
|
const router = useRouter()
|
||||||
|
const { backToList, goToEntry } = useQueryCRUDMode('mode')
|
||||||
|
const { recordId } = useQueryCRUDRecordId('record-id')
|
||||||
|
|
||||||
|
function onEditFromView() {
|
||||||
|
goToEntry({ fromView: true })
|
||||||
|
}
|
||||||
|
|
||||||
|
const props = defineProps<{
|
||||||
|
encounter: Encounter
|
||||||
|
}>()
|
||||||
|
|
||||||
|
// #endregion
|
||||||
|
|
||||||
|
// #region State & Computed
|
||||||
|
const reportData = ref<ActionReportFormData | null>(null)
|
||||||
|
|
||||||
|
const headerPrep: HeaderPrep = {
|
||||||
|
title: 'Detail Laporan Tindakan',
|
||||||
|
icon: 'i-lucide-stethoscope',
|
||||||
|
}
|
||||||
|
|
||||||
|
// #endregion
|
||||||
|
|
||||||
|
// #region Lifecycle Hooks
|
||||||
|
onMounted(async () => {
|
||||||
|
reportData.value = mockData as unknown as ActionReportFormData
|
||||||
|
})
|
||||||
|
// #endregion
|
||||||
|
|
||||||
|
// #region Functions
|
||||||
|
// #endregion region
|
||||||
|
|
||||||
|
// #region Utilities & event handlers
|
||||||
|
function onEdit() {
|
||||||
|
router.push({
|
||||||
|
name: 'action-report-id-edit',
|
||||||
|
params: { id: 100 },
|
||||||
|
})
|
||||||
|
}
|
||||||
|
function onBack() {}
|
||||||
|
// #endregion
|
||||||
|
|
||||||
|
// #region Watchers
|
||||||
|
// #endregion
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<AppActionReportPreview
|
||||||
|
v-if="reportData"
|
||||||
|
:data="reportData"
|
||||||
|
@back="backToList"
|
||||||
|
@edit="onEditFromView"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
@@ -1,61 +0,0 @@
|
|||||||
<script setup lang="ts">
|
|
||||||
import type { ExposedForm } from '~/types/form'
|
|
||||||
import { type AssessmentEducationFormData, AssessmentEducationSchema, encode } from '~/schemas/assessment-education'
|
|
||||||
import Action from '~/components/pub/my-ui/nav-footer/ba-dr-su.vue'
|
|
||||||
|
|
||||||
// Handlers
|
|
||||||
import {
|
|
||||||
isReadonly,
|
|
||||||
isProcessing,
|
|
||||||
onResetState,
|
|
||||||
handleActionSave,
|
|
||||||
handleCancelForm,
|
|
||||||
} from '~/handlers/assessment-education.handler'
|
|
||||||
|
|
||||||
// Helpers
|
|
||||||
import { toast } from '~/components/pub/ui/toast'
|
|
||||||
|
|
||||||
const form = ref<ExposedForm<AssessmentEducationFormData> | null>(null)
|
|
||||||
|
|
||||||
async function saveData(values: AssessmentEducationFormData) {
|
|
||||||
const transform = encode(1, values)
|
|
||||||
|
|
||||||
handleActionSave(
|
|
||||||
transform,
|
|
||||||
() => {
|
|
||||||
window.location.reload()
|
|
||||||
},
|
|
||||||
() => {},
|
|
||||||
toast,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
async function cancelData() {}
|
|
||||||
|
|
||||||
async function handleActionClick(eventType: string) {
|
|
||||||
if (eventType === 'submit') {
|
|
||||||
const formValidate = await form.value?.validate()
|
|
||||||
console.log(formValidate)
|
|
||||||
if (!formValidate?.valid) return
|
|
||||||
saveData(formValidate?.values)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (eventType === 'cancel') {
|
|
||||||
cancelData()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<template>
|
|
||||||
<div class="mb-5 border-b border-b-slate-300 pb-3 text-lg font-semibold xl:text-xl">Tambah Asesmen Edukasi</div>
|
|
||||||
<AppAssessmentEducationEntryForm
|
|
||||||
ref="form"
|
|
||||||
:is-readonly="isReadonly"
|
|
||||||
:is-loading="isProcessing"
|
|
||||||
:schema="AssessmentEducationSchema"
|
|
||||||
/>
|
|
||||||
|
|
||||||
<div class="my-2 flex justify-end py-2">
|
|
||||||
<Action @click="handleActionClick" />
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import List from './list.vue'
|
||||||
|
import Form from './form.vue'
|
||||||
|
import View from './view.vue'
|
||||||
|
|
||||||
|
// Models
|
||||||
|
import type { Encounter } from '~/models/encounter'
|
||||||
|
|
||||||
|
// Props
|
||||||
|
interface Props {
|
||||||
|
encounter: Encounter
|
||||||
|
}
|
||||||
|
|
||||||
|
const props = defineProps<Props>()
|
||||||
|
|
||||||
|
const { mode, goToEntry, goToView } = useQueryCRUDMode('mode')
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<List
|
||||||
|
v-if="mode === 'list'"
|
||||||
|
:encounter="props.encounter"
|
||||||
|
@add="goToEntry"
|
||||||
|
@edit="goToEntry({ fromView: false })"
|
||||||
|
@view="goToView"
|
||||||
|
/>
|
||||||
|
<View
|
||||||
|
v-else-if="mode === 'view'"
|
||||||
|
:encounter="props.encounter"
|
||||||
|
/>
|
||||||
|
<Form v-else />
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
@@ -0,0 +1,74 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import mockData from './sample'
|
||||||
|
|
||||||
|
// type
|
||||||
|
import { genDoctor, type Doctor } from '~/models/doctor'
|
||||||
|
import type { ActionReportFormData } from '~/schemas/action-report.schema'
|
||||||
|
|
||||||
|
// components
|
||||||
|
import { toast } from '~/components/pub/ui/toast'
|
||||||
|
import AppAssessmentEducationEntry from '~/components/app/assessment-education/entry.vue'
|
||||||
|
|
||||||
|
// states
|
||||||
|
const route = useRoute()
|
||||||
|
const { mode, goBack } = useQueryCRUDMode('mode')
|
||||||
|
const { recordId } = useQueryCRUDRecordId('record-id')
|
||||||
|
const reportData = ref<ActionReportFormData>({} as unknown as ActionReportFormData)
|
||||||
|
const doctors = ref<Doctor[]>([])
|
||||||
|
const isLoading = ref<boolean>(false)
|
||||||
|
|
||||||
|
// TODO: dummy data
|
||||||
|
;(() => {
|
||||||
|
doctors.value = [genDoctor()]
|
||||||
|
})()
|
||||||
|
|
||||||
|
const entryMode = ref<'add' | 'edit' | 'view'>('add')
|
||||||
|
const isDataReady = ref(false)
|
||||||
|
|
||||||
|
onMounted(async () => {
|
||||||
|
if (mode.value === 'entry' && recordId.value) {
|
||||||
|
entryMode.value = 'edit'
|
||||||
|
await loadEntryForEdit(+recordId.value)
|
||||||
|
} else {
|
||||||
|
// Untuk mode 'add', langsung set ready
|
||||||
|
isDataReady.value = true
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
// TODO: map data
|
||||||
|
async function loadEntryForEdit(id: number | string) {
|
||||||
|
isLoading.value = true
|
||||||
|
const result = mockData
|
||||||
|
reportData.value = result as ActionReportFormData
|
||||||
|
isLoading.value = false
|
||||||
|
isDataReady.value = true
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<AppAssessmentEducationEntry
|
||||||
|
v-if="isDataReady"
|
||||||
|
:isLoading="isLoading"
|
||||||
|
:mode="entryMode"
|
||||||
|
@submit="(val: {}) => console.log(val)"
|
||||||
|
@back="goBack"
|
||||||
|
@error="
|
||||||
|
(err: Error) => {
|
||||||
|
toast({
|
||||||
|
title: 'Terjadi Kesalahan',
|
||||||
|
description: err.message,
|
||||||
|
variant: 'destructive',
|
||||||
|
})
|
||||||
|
}
|
||||||
|
"
|
||||||
|
:doctors="doctors"
|
||||||
|
:initialValues="reportData"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<div
|
||||||
|
v-else
|
||||||
|
class="flex items-center justify-center p-8"
|
||||||
|
>
|
||||||
|
<p class="text-muted-foreground">Memuat data...</p>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
@@ -0,0 +1,276 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
// Components
|
||||||
|
import Dialog from '~/components/pub/my-ui/modal/dialog.vue'
|
||||||
|
import AppAssessmentEducationList from '~/components/app/assessment-education/list.vue'
|
||||||
|
import AppAssessmentEducationListHistory from '~/components/app/assessment-education/list-history.vue'
|
||||||
|
import RecordConfirmation from '~/components/pub/my-ui/confirmation/record-confirmation.vue'
|
||||||
|
import { ButtonAction } from '~/components/pub/my-ui/form'
|
||||||
|
|
||||||
|
// config
|
||||||
|
import { config } from '~/components/app/assessment-education/list.cfg'
|
||||||
|
|
||||||
|
// types
|
||||||
|
import { ActionEvents } from '~/components/pub/my-ui/data/types'
|
||||||
|
import type { Encounter } from '~/models/encounter'
|
||||||
|
|
||||||
|
// Samples
|
||||||
|
import { sampleRows, type AssessmentEducationData } from '~/components/app/assessment-education/sample'
|
||||||
|
import sampleReport from './sample'
|
||||||
|
|
||||||
|
// helpers
|
||||||
|
import { toast } from '~/components/pub/ui/toast'
|
||||||
|
|
||||||
|
// Props
|
||||||
|
interface Props {
|
||||||
|
encounter: Encounter
|
||||||
|
}
|
||||||
|
const props = defineProps<Props>()
|
||||||
|
const emits = defineEmits<{
|
||||||
|
(e: 'add'): void
|
||||||
|
(e: 'edit', id: number | string): void
|
||||||
|
(e: 'view', id: number | string): void
|
||||||
|
}>()
|
||||||
|
|
||||||
|
// states
|
||||||
|
const router = useRouter()
|
||||||
|
const route = useRoute()
|
||||||
|
const { goToEntry, backToList } = useQueryCRUDMode('mode')
|
||||||
|
const title = ref('')
|
||||||
|
const search = ref('')
|
||||||
|
const dateFrom = ref('')
|
||||||
|
const dateTo = ref('')
|
||||||
|
const isDialogOpen = ref<boolean>(false)
|
||||||
|
const isLoading = ref<boolean>(false)
|
||||||
|
|
||||||
|
// #region mock
|
||||||
|
// Handlers
|
||||||
|
import {
|
||||||
|
recId,
|
||||||
|
recAction,
|
||||||
|
recItem,
|
||||||
|
isReadonly,
|
||||||
|
isProcessing,
|
||||||
|
isFormEntryDialogOpen,
|
||||||
|
isRecordConfirmationOpen,
|
||||||
|
onResetState,
|
||||||
|
handleActionSave,
|
||||||
|
handleActionEdit,
|
||||||
|
handleActionRemove,
|
||||||
|
handleCancelForm,
|
||||||
|
} from '~/handlers/consultation.handler'
|
||||||
|
// #endregion
|
||||||
|
|
||||||
|
// filter + pencarian sederhana (client-side)
|
||||||
|
const filtered = computed(() => {
|
||||||
|
const q = search.value.trim().toLowerCase()
|
||||||
|
return sampleRows.filter((r: ActionReportData) => {
|
||||||
|
if (q) {
|
||||||
|
return r.nama.toLowerCase().includes(q) || r.noRm.toLowerCase().includes(q) || r.dokter.toLowerCase().includes(q)
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
const goEdit = (id: number | string) => {
|
||||||
|
router.replace({
|
||||||
|
path: route.path,
|
||||||
|
query: {
|
||||||
|
...route.query,
|
||||||
|
mode: 'entry',
|
||||||
|
'record-id': id,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const goView = (id: number | string) => {
|
||||||
|
router.replace({
|
||||||
|
path: route.path,
|
||||||
|
query: {
|
||||||
|
...route.query,
|
||||||
|
mode: 'view',
|
||||||
|
'record-id': id,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
provide('rec_id', recId)
|
||||||
|
provide('rec_action', recAction)
|
||||||
|
provide('rec_item', recItem)
|
||||||
|
provide('table_data_loader', isLoading)
|
||||||
|
|
||||||
|
async function onGetDetail(id: number | string) {
|
||||||
|
isLoading.value = true
|
||||||
|
const res = sampleReport
|
||||||
|
recItem.value = res
|
||||||
|
console.log(res)
|
||||||
|
isLoading.value = false
|
||||||
|
}
|
||||||
|
|
||||||
|
// #region watcher
|
||||||
|
watch([recId, recAction], (newVal) => {
|
||||||
|
const [id, action] = newVal
|
||||||
|
|
||||||
|
// Guard: jangan proses jika id = 0 atau action kosong
|
||||||
|
if (!id || !action) return
|
||||||
|
|
||||||
|
switch (action) {
|
||||||
|
case ActionEvents.showDetail:
|
||||||
|
// onGetDetail(recId.value)
|
||||||
|
goView(id)
|
||||||
|
title.value = 'Detail Konsultasi'
|
||||||
|
break
|
||||||
|
case ActionEvents.showEdit:
|
||||||
|
goEdit(id)
|
||||||
|
title.value = 'Edit Konsultasi'
|
||||||
|
break
|
||||||
|
case ActionEvents.showConfirmDelete:
|
||||||
|
isRecordConfirmationOpen.value = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reset KEDUANYA menggunakan nextTick agar tidak trigger watcher lagi
|
||||||
|
nextTick(() => {
|
||||||
|
recId.value = 0
|
||||||
|
recAction.value = ''
|
||||||
|
})
|
||||||
|
})
|
||||||
|
// #endregion
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="mx-auto max-w-full">
|
||||||
|
<div class="border-b p-6">
|
||||||
|
<h1 class="text-2xl font-semibold">Asesmen Kebutuhan Edukasi</h1>
|
||||||
|
<p class="mt-1 text-sm text-gray-500">Manajemen asesmen kebutuhan edukasi pasien rawat jalan</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="flex flex-wrap items-center gap-3 border-b p-4">
|
||||||
|
<div class="flex items-center gap-2">
|
||||||
|
<input
|
||||||
|
v-model="search"
|
||||||
|
placeholder="Cari Nama / No.RM"
|
||||||
|
class="w-64 rounded border px-3 py-2"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="flex items-center gap-2">
|
||||||
|
<input
|
||||||
|
v-model="dateFrom"
|
||||||
|
type="date"
|
||||||
|
class="rounded border px-3 py-2"
|
||||||
|
/>
|
||||||
|
<span class="text-sm text-gray-500">-</span>
|
||||||
|
<input
|
||||||
|
v-model="dateTo"
|
||||||
|
type="date"
|
||||||
|
class="rounded border px-3 py-2"
|
||||||
|
/>
|
||||||
|
<ButtonAction
|
||||||
|
preset="custom"
|
||||||
|
title="Filter List Asesmen"
|
||||||
|
label="Filter"
|
||||||
|
icon="i-lucide-filter"
|
||||||
|
@click="
|
||||||
|
() => {
|
||||||
|
isDialogOpen = true
|
||||||
|
}
|
||||||
|
"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="ml-auto flex items-center gap-2">
|
||||||
|
<ButtonAction
|
||||||
|
preset="custom"
|
||||||
|
title="Riwayat"
|
||||||
|
icon="i-lucide-history"
|
||||||
|
label="Riwayat"
|
||||||
|
@click="
|
||||||
|
() => {
|
||||||
|
isDialogOpen = true
|
||||||
|
}
|
||||||
|
"
|
||||||
|
/>
|
||||||
|
<ButtonAction
|
||||||
|
preset="add"
|
||||||
|
title="Tambah Asesmen"
|
||||||
|
icon="i-lucide-plus"
|
||||||
|
label="Asesmen"
|
||||||
|
@click="
|
||||||
|
() => {
|
||||||
|
goToEntry()
|
||||||
|
}
|
||||||
|
"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="overflow-x-auto p-4">
|
||||||
|
<AppAssessmentEducationList
|
||||||
|
:data="filtered"
|
||||||
|
:pagination-meta="{
|
||||||
|
recordCount: 2,
|
||||||
|
page: 1,
|
||||||
|
pageSize: 10,
|
||||||
|
totalPage: 1,
|
||||||
|
hasPrev: false,
|
||||||
|
hasNext: false,
|
||||||
|
}"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<Dialog
|
||||||
|
v-model:open="isDialogOpen"
|
||||||
|
title="Arsip Riwayat Asesmen Kebutuhan Edukasi"
|
||||||
|
size="2xl"
|
||||||
|
prevent-outside
|
||||||
|
@update:open="
|
||||||
|
(value: any) => {
|
||||||
|
isDialogOpen = value
|
||||||
|
}
|
||||||
|
"
|
||||||
|
>
|
||||||
|
<AppAssessmentEducationListHistory
|
||||||
|
:data="filtered"
|
||||||
|
:pagination-meta="{
|
||||||
|
recordCount: 2,
|
||||||
|
page: 1,
|
||||||
|
pageSize: 10,
|
||||||
|
totalPage: 1,
|
||||||
|
hasPrev: false,
|
||||||
|
hasNext: false,
|
||||||
|
}"
|
||||||
|
/>
|
||||||
|
</Dialog>
|
||||||
|
|
||||||
|
<RecordConfirmation
|
||||||
|
v-model:open="isRecordConfirmationOpen"
|
||||||
|
action="delete"
|
||||||
|
:record="recItem"
|
||||||
|
@confirm="
|
||||||
|
() =>
|
||||||
|
handleActionRemove(
|
||||||
|
recItem.id,
|
||||||
|
() => {
|
||||||
|
router.go(0)
|
||||||
|
},
|
||||||
|
toast,
|
||||||
|
)
|
||||||
|
"
|
||||||
|
@cancel=""
|
||||||
|
>
|
||||||
|
<template #default="{ record }">
|
||||||
|
{{ console.log(JSON.stringify(record)) }}
|
||||||
|
<div class="space-y-1 text-sm">
|
||||||
|
<p
|
||||||
|
v-for="field in config.delKeyNames"
|
||||||
|
:key="field.key"
|
||||||
|
:v-if="record?.[field.key]"
|
||||||
|
>
|
||||||
|
<span class="font-semibold">{{ field.label }}:</span>
|
||||||
|
{{ record[field.key] }}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</RecordConfirmation>
|
||||||
|
</template>
|
||||||
@@ -0,0 +1,68 @@
|
|||||||
|
export default {
|
||||||
|
operatorTeam: {
|
||||||
|
dpjpId: -1,
|
||||||
|
operatorName: 'Julian Alvarez',
|
||||||
|
assistantOperatorName: 'Arda Guller',
|
||||||
|
instrumentNurseName: 'Kenan Yildiz',
|
||||||
|
surgeryDate: '2025-11-13T14:29:00',
|
||||||
|
actionDiagnosis: 'Sprei gratisnya mana',
|
||||||
|
},
|
||||||
|
procedures: [
|
||||||
|
{
|
||||||
|
id: -1,
|
||||||
|
name: 'Ndase mumet',
|
||||||
|
code: 'CX1',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
operationExecution: {
|
||||||
|
surgeryType: 'khusus',
|
||||||
|
billingCode: 'local',
|
||||||
|
operationSystem: 'cito',
|
||||||
|
surgeryCleanType: 'kotor',
|
||||||
|
surgeryNumber: 'retry',
|
||||||
|
birthPlaceNote: 'out3',
|
||||||
|
personWeight: 100,
|
||||||
|
operationDescription: 'asdsadsa1',
|
||||||
|
birthRemark: 'lahir_hidup',
|
||||||
|
|
||||||
|
operationStartAt: '2025-11-13T14:29:00',
|
||||||
|
operationEndAt: '2025-11-13T17:29:00',
|
||||||
|
|
||||||
|
anesthesiaStartAt: '2025-11-13T11:29:00',
|
||||||
|
anesthesiaEndAt: '2025-11-13T18:29:00',
|
||||||
|
},
|
||||||
|
bloodInput: {
|
||||||
|
type: 'tc',
|
||||||
|
amount: {
|
||||||
|
prc: null,
|
||||||
|
wb: null,
|
||||||
|
ffp: null,
|
||||||
|
tc: 3243324,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
implant: {
|
||||||
|
brand: 'Samsung',
|
||||||
|
name: 'S.Komedi',
|
||||||
|
companionName: 'When ya',
|
||||||
|
},
|
||||||
|
specimen: {
|
||||||
|
destination: 'pa',
|
||||||
|
},
|
||||||
|
tissueNotes: [
|
||||||
|
{
|
||||||
|
note: 'Anjai',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
note: 'Ciee Kaget',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
note: 'Baper',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
note: 'Saltink weeh',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
note: 'Kaburrr',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}
|
||||||
@@ -0,0 +1,67 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import mockData from './sample'
|
||||||
|
|
||||||
|
// types
|
||||||
|
import { type ActionReportFormData } from '~/schemas/action-report.schema'
|
||||||
|
import { type Encounter } from '~/models/encounter'
|
||||||
|
|
||||||
|
// Components
|
||||||
|
import AppActionReportPreview from '~/components/app/action-report/preview.vue'
|
||||||
|
import type { HeaderPrep } from '~/components/pub/my-ui/data/types'
|
||||||
|
|
||||||
|
// #region Props & Emits
|
||||||
|
const router = useRouter()
|
||||||
|
const { backToList, goToEntry } = useQueryCRUDMode('mode')
|
||||||
|
const { recordId } = useQueryCRUDRecordId('record-id')
|
||||||
|
|
||||||
|
function onEditFromView() {
|
||||||
|
goToEntry({ fromView: true })
|
||||||
|
}
|
||||||
|
|
||||||
|
const props = defineProps<{
|
||||||
|
encounter: Encounter
|
||||||
|
}>()
|
||||||
|
|
||||||
|
// #endregion
|
||||||
|
|
||||||
|
// #region State & Computed
|
||||||
|
const reportData = ref<ActionReportFormData | null>(null)
|
||||||
|
|
||||||
|
const headerPrep: HeaderPrep = {
|
||||||
|
title: 'Detail Laporan Tindakan',
|
||||||
|
icon: 'i-lucide-stethoscope',
|
||||||
|
}
|
||||||
|
|
||||||
|
// #endregion
|
||||||
|
|
||||||
|
// #region Lifecycle Hooks
|
||||||
|
onMounted(async () => {
|
||||||
|
reportData.value = mockData as unknown as ActionReportFormData
|
||||||
|
})
|
||||||
|
// #endregion
|
||||||
|
|
||||||
|
// #region Functions
|
||||||
|
// #endregion region
|
||||||
|
|
||||||
|
// #region Utilities & event handlers
|
||||||
|
function onEdit() {
|
||||||
|
router.push({
|
||||||
|
name: 'action-report-id-edit',
|
||||||
|
params: { id: 100 },
|
||||||
|
})
|
||||||
|
}
|
||||||
|
function onBack() {}
|
||||||
|
// #endregion
|
||||||
|
|
||||||
|
// #region Watchers
|
||||||
|
// #endregion
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<AppActionReportPreview
|
||||||
|
v-if="reportData"
|
||||||
|
:data="reportData"
|
||||||
|
@back="backToList"
|
||||||
|
@edit="onEditFromView"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
@@ -45,16 +45,18 @@ const MicroLabOrderAsync = defineAsyncComponent(() => import('~/components/conte
|
|||||||
const CprjAsync = defineAsyncComponent(() => import('~/components/content/cprj/entry.vue'))
|
const CprjAsync = defineAsyncComponent(() => import('~/components/content/cprj/entry.vue'))
|
||||||
const RadiologyAsync = defineAsyncComponent(() => import('~/components/content/radiology-order/main.vue'))
|
const RadiologyAsync = defineAsyncComponent(() => import('~/components/content/radiology-order/main.vue'))
|
||||||
const ConsultationAsync = defineAsyncComponent(() => import('~/components/content/consultation/list.vue'))
|
const ConsultationAsync = defineAsyncComponent(() => import('~/components/content/consultation/list.vue'))
|
||||||
const DocUploadListAsync = defineAsyncComponent(() => import('~/components/content/document-upload/main.vue'))
|
const DocUploadListAsync = defineAsyncComponent(() => import('~/components/content/document-upload/list.vue'))
|
||||||
const GeneralConsentListAsync = defineAsyncComponent(() => import('~/components/content/general-consent/entry.vue'))
|
const GeneralConsentListAsync = defineAsyncComponent(() => import('~/components/content/general-consent/entry.vue'))
|
||||||
const ResumeListAsync = defineAsyncComponent(() => import('~/components/content/resume/main.vue'))
|
const ResumeListAsync = defineAsyncComponent(() => import('~/components/content/resume/list.vue'))
|
||||||
const ControlLetterListAsync = defineAsyncComponent(() => import('~/components/content/control-letter/main.vue'))
|
const ControlLetterListAsync = defineAsyncComponent(() => import('~/components/content/control-letter/list.vue'))
|
||||||
const KfrListAsync = defineAsyncComponent(() => import('~/components/content/kfr/main.vue'))
|
const KfrListAsync = defineAsyncComponent(() => import('~/components/content/kfr/list.vue'))
|
||||||
const PrbListAsync = defineAsyncComponent(() => import('~/components/content/prb/main.vue'))
|
const PrbListAsync = defineAsyncComponent(() => import('~/components/content/prb/list.vue'))
|
||||||
const SurgeryReportListAsync = defineAsyncComponent(() => import('~/components/content/surgery-report/main.vue'))
|
const SurgeryReportListAsync = defineAsyncComponent(() => import('~/components/content/surgery-report/list.vue'))
|
||||||
const VaccineDataListAsync = defineAsyncComponent(() => import('~/components/content/vaccine-data/main.vue'))
|
const VaccineDataListAsync = defineAsyncComponent(() => import('~/components/content/vaccine-data/list.vue'))
|
||||||
const InitialNursingStudyAsync = defineAsyncComponent(() => import('~/components/content/initial-nursing/entry.vue'))
|
const InitialNursingStudyAsync = defineAsyncComponent(() => import('~/components/content/initial-nursing/entry.vue'))
|
||||||
const SummaryMedicAsync = defineAsyncComponent(() => import('~/components/content/summary-medic/entry.vue'))
|
const AssessmentEducationEntryAsync = defineAsyncComponent(
|
||||||
|
() => import('~/components/content/assessment-education/entry.vue'),
|
||||||
|
)
|
||||||
|
|
||||||
const defaultKeys: Record<string, any> = {
|
const defaultKeys: Record<string, any> = {
|
||||||
status: {
|
status: {
|
||||||
@@ -63,19 +65,17 @@ const defaultKeys: Record<string, any> = {
|
|||||||
classCode: ['ambulatory', 'emergency', 'inpatient'],
|
classCode: ['ambulatory', 'emergency', 'inpatient'],
|
||||||
unit: 'all',
|
unit: 'all',
|
||||||
},
|
},
|
||||||
// NOTE : HIDDEN UNTIL IT IS READY
|
earlyNurseryAssessment: {
|
||||||
// earlyNurseryAssessment: {
|
id: 'early-nursery-assessment',
|
||||||
// id: 'early-nursery-assessment',
|
title: 'Pengkajian Awal Keperawatan',
|
||||||
// title: 'Pengkajian Awal Keperawatan',
|
classCode: ['ambulatory', 'emergency', 'inpatient'],
|
||||||
// classCode: ['ambulatory', 'emergency', 'inpatient'],
|
unit: 'all',
|
||||||
// unit: 'all',
|
},
|
||||||
// },
|
|
||||||
earlyMedicalAssessment: {
|
earlyMedicalAssessment: {
|
||||||
id: 'early-medical-assessment',
|
id: 'early-medical-assessment',
|
||||||
title: 'Pengkajian Awal Medis',
|
title: 'Pengkajian Awal Medis',
|
||||||
classCode: ['ambulatory', 'emergency', 'inpatient'],
|
classCode: ['ambulatory', 'emergency', 'inpatient'],
|
||||||
unit: 'all',
|
unit: 'all',
|
||||||
afterId: 'early-medical-assessment',
|
|
||||||
},
|
},
|
||||||
earlyMedicalRehabAssessment: {
|
earlyMedicalRehabAssessment: {
|
||||||
id: 'rehab-medical-assessment',
|
id: 'rehab-medical-assessment',
|
||||||
@@ -84,27 +84,20 @@ const defaultKeys: Record<string, any> = {
|
|||||||
unit: 'rehab',
|
unit: 'rehab',
|
||||||
afterId: 'early-medical-assessment',
|
afterId: 'early-medical-assessment',
|
||||||
},
|
},
|
||||||
fkr: {
|
functionAssessment: {
|
||||||
id: 'fkr',
|
id: 'function-assessment',
|
||||||
title: 'FKR',
|
title: 'Asesmen Fungsi',
|
||||||
classCode: ['ambulatory', 'emergency', 'inpatient'],
|
classCode: ['ambulatory'],
|
||||||
unit: 'all',
|
unit: 'rehab',
|
||||||
|
afterId: 'rehab-medical-assessment',
|
||||||
|
},
|
||||||
|
therapyProtocol: {
|
||||||
|
id: 'therapy-protocol',
|
||||||
|
classCode: ['ambulatory'],
|
||||||
|
title: 'Protokol Terapi',
|
||||||
|
unit: 'rehab',
|
||||||
|
afterId: 'function-assessment',
|
||||||
},
|
},
|
||||||
// NOTE: Replaced by FRK
|
|
||||||
// functionAssessment: {
|
|
||||||
// id: 'function-assessment',
|
|
||||||
// title: 'Asesmen Fungsi',
|
|
||||||
// classCode: ['ambulatory'],
|
|
||||||
// unit: 'rehab',
|
|
||||||
// afterId: 'rehab-medical-assessment',
|
|
||||||
// },
|
|
||||||
// therapyProtocol: {
|
|
||||||
// id: 'therapy-protocol',
|
|
||||||
// classCode: ['ambulatory'],
|
|
||||||
// title: 'Protokol Terapi',
|
|
||||||
// unit: 'rehab',
|
|
||||||
// afterId: 'function-assessment',
|
|
||||||
// },
|
|
||||||
chemotherapyProtocol: {
|
chemotherapyProtocol: {
|
||||||
id: 'chemotherapy-protocol',
|
id: 'chemotherapy-protocol',
|
||||||
title: 'Protokol Kemoterapi',
|
title: 'Protokol Kemoterapi',
|
||||||
@@ -227,6 +220,12 @@ const defaultKeys: Record<string, any> = {
|
|||||||
classCode: ['ambulatory', 'emergency'],
|
classCode: ['ambulatory', 'emergency'],
|
||||||
unit: 'all',
|
unit: 'all',
|
||||||
},
|
},
|
||||||
|
kfr: {
|
||||||
|
id: 'kfr',
|
||||||
|
title: 'KFR',
|
||||||
|
classCode: ['ambulatory', 'emergency', 'inpatient'],
|
||||||
|
unit: 'all',
|
||||||
|
},
|
||||||
refBack: {
|
refBack: {
|
||||||
id: 'reference-back',
|
id: 'reference-back',
|
||||||
title: 'PRB',
|
title: 'PRB',
|
||||||
@@ -263,12 +262,6 @@ const defaultKeys: Record<string, any> = {
|
|||||||
classCode: ['ambulatory', 'emergency', 'inpatient'],
|
classCode: ['ambulatory', 'emergency', 'inpatient'],
|
||||||
unit: 'all',
|
unit: 'all',
|
||||||
},
|
},
|
||||||
summaryMedic: {
|
|
||||||
id: 'summary-medic',
|
|
||||||
title: 'Profil Ringkasan Medis',
|
|
||||||
classCode: ['ambulatory', 'emergency', 'inpatient'],
|
|
||||||
unit: 'all',
|
|
||||||
},
|
|
||||||
initialNursingStudy: {
|
initialNursingStudy: {
|
||||||
id: 'initial-nursing-study',
|
id: 'initial-nursing-study',
|
||||||
title: 'Kajian Awal Keperawatan',
|
title: 'Kajian Awal Keperawatan',
|
||||||
@@ -360,9 +353,12 @@ export function injectComponents(id: string | number, data: EncounterListData, m
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (currentKeys?.educationAssessment) {
|
if (currentKeys?.educationAssessment) {
|
||||||
// TODO: add component for education assessment
|
currentKeys.educationAssessment['component'] = AssessmentEducationEntryAsync
|
||||||
currentKeys.educationAssessment['component'] = null
|
currentKeys.educationAssessment['props'] = {
|
||||||
currentKeys.educationAssessment['props'] = { encounter_id: id }
|
encounter: data?.encounter,
|
||||||
|
type: 'education-assessment',
|
||||||
|
label: currentKeys.educationAssessment['title'],
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (currentKeys?.generalConsent) {
|
if (currentKeys?.generalConsent) {
|
||||||
currentKeys.generalConsent['component'] = GeneralConsentListAsync
|
currentKeys.generalConsent['component'] = GeneralConsentListAsync
|
||||||
@@ -422,9 +418,9 @@ export function injectComponents(id: string | number, data: EncounterListData, m
|
|||||||
currentKeys.refBack['component'] = PrbListAsync
|
currentKeys.refBack['component'] = PrbListAsync
|
||||||
currentKeys.refBack['props'] = { encounter: data?.encounter }
|
currentKeys.refBack['props'] = { encounter: data?.encounter }
|
||||||
}
|
}
|
||||||
if (currentKeys?.fkr) {
|
if (currentKeys?.kfr) {
|
||||||
currentKeys.fkr['component'] = KfrListAsync
|
currentKeys.kfr['component'] = KfrListAsync
|
||||||
currentKeys.fkr['props'] = { encounter: data?.encounter }
|
currentKeys.kfr['props'] = { encounter: data?.encounter }
|
||||||
}
|
}
|
||||||
if (currentKeys?.screening) {
|
if (currentKeys?.screening) {
|
||||||
// TODO: add component for screening
|
// TODO: add component for screening
|
||||||
@@ -448,10 +444,12 @@ export function injectComponents(id: string | number, data: EncounterListData, m
|
|||||||
currentKeys.priceList['component'] = null
|
currentKeys.priceList['component'] = null
|
||||||
currentKeys.priceList['props'] = { encounter_id: id }
|
currentKeys.priceList['props'] = { encounter_id: id }
|
||||||
}
|
}
|
||||||
if (currentKeys?.summaryMedic) {
|
|
||||||
currentKeys.summaryMedic['component'] = SummaryMedicAsync
|
if (currentKeys?.initialNursingStudy) {
|
||||||
currentKeys.summaryMedic['props'] = { encounter_id: id }
|
currentKeys.initialNursingStudy['component'] = InitialNursingStudyAsync
|
||||||
|
currentKeys.initialNursingStudy['props'] = { encounter: data?.encounter }
|
||||||
}
|
}
|
||||||
|
|
||||||
if (currentKeys?.initialNursingStudy) {
|
if (currentKeys?.initialNursingStudy) {
|
||||||
currentKeys.initialNursingStudy['component'] = InitialNursingStudyAsync
|
currentKeys.initialNursingStudy['component'] = InitialNursingStudyAsync
|
||||||
currentKeys.initialNursingStudy['props'] = { encounter: data?.encounter }
|
currentKeys.initialNursingStudy['props'] = { encounter: data?.encounter }
|
||||||
@@ -512,12 +510,9 @@ export function mapResponseToEncounter(result: any): any {
|
|||||||
? result.visitDate
|
? result.visitDate
|
||||||
: result.registeredAt || result.patient?.registeredAt || null,
|
: result.registeredAt || result.patient?.registeredAt || null,
|
||||||
adm_employee_id: result.adm_employee_id || 0,
|
adm_employee_id: result.adm_employee_id || 0,
|
||||||
adm_employee: result.adm_employee || null,
|
appointment_doctor_id: result.appointment_doctor_id || null,
|
||||||
responsible_nurse_code: result.responsible_nurse_code || null,
|
responsible_doctor_id: result.responsible_doctor_id || null,
|
||||||
responsible_nurse: result.responsible_nurse || null,
|
|
||||||
appointment_doctor_code: result.appointment_doctor_code || null,
|
|
||||||
appointment_doctor: result.appointment_doctor || null,
|
appointment_doctor: result.appointment_doctor || null,
|
||||||
responsible_doctor_code: result.responsible_doctor_id || null,
|
|
||||||
responsible_doctor: result.responsible_doctor || null,
|
responsible_doctor: result.responsible_doctor || null,
|
||||||
refSource_name: result.refSource_name || null,
|
refSource_name: result.refSource_name || null,
|
||||||
appointment_id: result.appointment_id || null,
|
appointment_id: result.appointment_id || null,
|
||||||
@@ -539,13 +534,7 @@ export function mapResponseToEncounter(result: any): any {
|
|||||||
return mapped
|
return mapped
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getMenuItems(
|
export function getMenuItems(id: string | number, props: any, user: any, data: EncounterListData, meta: any) {
|
||||||
id: string | number,
|
|
||||||
props: any,
|
|
||||||
user: any,
|
|
||||||
data: EncounterListData,
|
|
||||||
meta: any,
|
|
||||||
) {
|
|
||||||
// const normalClassCode = props.classCode === 'ambulatory' ? 'outpatient' : props.classCode
|
// const normalClassCode = props.classCode === 'ambulatory' ? 'outpatient' : props.classCode
|
||||||
const normalClassCode = props.classCode === 'ambulatory' ? 'ambulatory' : props.classCode
|
const normalClassCode = props.classCode === 'ambulatory' ? 'ambulatory' : props.classCode
|
||||||
const currentKeys = injectComponents(id, data, meta)
|
const currentKeys = injectComponents(id, data, meta)
|
||||||
|
|||||||
+3
-2
@@ -1,4 +1,3 @@
|
|||||||
|
|
||||||
export interface Base {
|
export interface Base {
|
||||||
id: number
|
id: number
|
||||||
createdAt: string | null
|
createdAt: string | null
|
||||||
@@ -20,7 +19,9 @@ export interface TreeItem {
|
|||||||
|
|
||||||
export function genBase(): Base {
|
export function genBase(): Base {
|
||||||
return {
|
return {
|
||||||
id: 0,
|
// -1 buat mock data
|
||||||
|
// backend harusnya non-negative/ > 0 (untuk auto increment constraint) jadi harusnya aman ya
|
||||||
|
id: -1,
|
||||||
createdAt: '',
|
createdAt: '',
|
||||||
updatedAt: '',
|
updatedAt: '',
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
import { type Base, genBase } from "./_base"
|
import { type Base, genBase } from './_base'
|
||||||
import { type Employee, genEmployee } from "./employee"
|
import { type Employee, genEmployee } from './employee'
|
||||||
import type { Unit } from "./unit"
|
import type { Unit } from './unit'
|
||||||
import type { Specialist } from "./specialist"
|
import type { Specialist } from './specialist'
|
||||||
import type { Subspecialist } from "./subspecialist"
|
import type { Subspecialist } from './subspecialist'
|
||||||
|
|
||||||
export interface Doctor extends Base {
|
export interface Doctor extends Base {
|
||||||
employee_id: number
|
employee_id: number
|
||||||
|
|||||||
@@ -1,41 +0,0 @@
|
|||||||
import { type Base, genBase } from './_base'
|
|
||||||
|
|
||||||
export type JsonRaw = string
|
|
||||||
|
|
||||||
export interface EduAssessment extends Base {
|
|
||||||
encounter_id: number
|
|
||||||
generalEdus: Record<string, string>
|
|
||||||
specialEdus: Record<string, string>
|
|
||||||
assessments: Record<string, string>
|
|
||||||
plan: Record<string, string>
|
|
||||||
}
|
|
||||||
|
|
||||||
export function genEduAssessment(): EduAssessment {
|
|
||||||
return {
|
|
||||||
...genBase(),
|
|
||||||
encounter_id: 0,
|
|
||||||
generalEdus: {},
|
|
||||||
specialEdus: {},
|
|
||||||
assessments: {},
|
|
||||||
plan: {},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface EduAssessmentRaw extends Base {
|
|
||||||
encounter_id: number
|
|
||||||
generalEdus: string
|
|
||||||
specialEdus: string
|
|
||||||
assessments: string
|
|
||||||
plan: string
|
|
||||||
}
|
|
||||||
|
|
||||||
export function genEduAssessmentRaw(): EduAssessmentRaw {
|
|
||||||
return {
|
|
||||||
...genBase(),
|
|
||||||
encounter_id: 0,
|
|
||||||
generalEdus: '',
|
|
||||||
specialEdus: '',
|
|
||||||
assessments: '',
|
|
||||||
plan: '',
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -52,7 +52,7 @@ export function genEncounter(): Encounter {
|
|||||||
patient: genPatient(),
|
patient: genPatient(),
|
||||||
registeredAt: '',
|
registeredAt: '',
|
||||||
class_code: '',
|
class_code: '',
|
||||||
unit_code: '',
|
unit_code: 0,
|
||||||
unit: genUnit(),
|
unit: genUnit(),
|
||||||
visitDate: '',
|
visitDate: '',
|
||||||
adm_employee_id: 0,
|
adm_employee_id: 0,
|
||||||
|
|||||||
@@ -1,9 +1,7 @@
|
|||||||
import { type Base, genBase } from "./_base"
|
import { type Base, genBase } from "./_base"
|
||||||
import type { Employee } from "./employee"
|
|
||||||
|
|
||||||
export interface Nurse extends Base {
|
export interface Nurse extends Base {
|
||||||
employee_id: number
|
employee_id: number
|
||||||
employee?: Employee
|
|
||||||
ihs_number?: string
|
ihs_number?: string
|
||||||
unit_id: number
|
unit_id: number
|
||||||
infra_id: number
|
infra_id: number
|
||||||
|
|||||||
+14
-5
@@ -1,7 +1,7 @@
|
|||||||
import { type Base, genBase } from "./_base"
|
import { type Base, genBase } from './_base'
|
||||||
import type { PersonAddress } from "./person-address"
|
import type { PersonAddress } from './person-address'
|
||||||
import type { PersonContact } from "./person-contact"
|
import type { PersonContact } from './person-contact'
|
||||||
import type { PersonRelative } from "./person-relative"
|
import type { PersonRelative } from './person-relative'
|
||||||
import type { Ethnic } from './ethnic'
|
import type { Ethnic } from './ethnic'
|
||||||
import type { Language } from './language'
|
import type { Language } from './language'
|
||||||
import type { Regency } from './regency'
|
import type { Regency } from './regency'
|
||||||
@@ -43,6 +43,15 @@ export interface Person extends Base {
|
|||||||
export function genPerson(): Person {
|
export function genPerson(): Person {
|
||||||
return {
|
return {
|
||||||
...genBase(),
|
...genBase(),
|
||||||
name: '',
|
frontTitle: '[MOCK] dr. ',
|
||||||
|
name: 'Agus Iwan Setiawan',
|
||||||
|
endTitle: 'Sp.Bo',
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function parseName(person: Person): string {
|
||||||
|
if (!person) return ''
|
||||||
|
const fullName = [person.frontTitle, person.name, person.endTitle].filter(Boolean).join(' ').trim()
|
||||||
|
|
||||||
|
return fullName
|
||||||
|
}
|
||||||
@@ -0,0 +1,121 @@
|
|||||||
|
import { z } from 'zod'
|
||||||
|
|
||||||
|
const isoDateTime = z
|
||||||
|
.string()
|
||||||
|
.min(1, 'Tanggal / waktu wajib diisi')
|
||||||
|
.refine((val) => {
|
||||||
|
const date = new Date(val)
|
||||||
|
return !isNaN(date.getTime())
|
||||||
|
}, 'Format tanggal / waktu tidak valid')
|
||||||
|
|
||||||
|
const positiveInt = z.coerce.number().int().nonnegative()
|
||||||
|
|
||||||
|
const OperatorTeamSchema = z.object({
|
||||||
|
dpjpId: z.coerce
|
||||||
|
.number({
|
||||||
|
invalid_type_error: 'Silahkan pilih dpjp terlebih dahulu',
|
||||||
|
})
|
||||||
|
.int(),
|
||||||
|
operatorName: z.string({
|
||||||
|
required_error: 'Masukkan nama operator',
|
||||||
|
}),
|
||||||
|
assistantOperatorName: z.string({
|
||||||
|
required_error: 'Masukkan nama asisten operator',
|
||||||
|
}),
|
||||||
|
instrumentNurseName: z.string({
|
||||||
|
required_error: 'Masukkan nama instrumentir',
|
||||||
|
}),
|
||||||
|
|
||||||
|
surgeryDate: isoDateTime,
|
||||||
|
actionDiagnosis: z.string(),
|
||||||
|
|
||||||
|
postSurgeryNurseId: z.number().int().optional().nullable(),
|
||||||
|
})
|
||||||
|
|
||||||
|
const ProcedureSchema = z.object({
|
||||||
|
id: z.number().int(),
|
||||||
|
name: z.string().min(1),
|
||||||
|
code: z.string().min(1),
|
||||||
|
})
|
||||||
|
|
||||||
|
const OperationExecutionSchema = z.object({
|
||||||
|
surgeryType: z.enum(['kecil', 'sedang', 'besar', 'khusus'], { required_error: 'Silahkan pilih jenis operasi' }),
|
||||||
|
billingCode: z.string({
|
||||||
|
required_error: 'Silahkan pilih kode billing',
|
||||||
|
}),
|
||||||
|
operationSystem: z.enum(['khusus', 'cito', 'efektif', 'urgent'], { required_error: 'Silahkan pilih sistem operasi' }),
|
||||||
|
|
||||||
|
operationStartAt: isoDateTime,
|
||||||
|
operationEndAt: isoDateTime,
|
||||||
|
|
||||||
|
anesthesiaStartAt: isoDateTime,
|
||||||
|
anesthesiaEndAt: isoDateTime,
|
||||||
|
|
||||||
|
surgeryCleanType: z.enum(['bersih', 'bersih_terkontaminasi', 'terkontaminasi', 'kotor']).optional(),
|
||||||
|
surgeryNumber: z.enum(['first', 'retry']).optional(),
|
||||||
|
|
||||||
|
birthPlaceNote: z.string().optional(),
|
||||||
|
personWeight: positiveInt.optional(),
|
||||||
|
birthCondition: z.string().optional(),
|
||||||
|
|
||||||
|
operationDescription: z.string({
|
||||||
|
required_error: 'Mohon lengkapi uraian operasi',
|
||||||
|
}),
|
||||||
|
|
||||||
|
bleedingAmountCc: positiveInt.optional(),
|
||||||
|
|
||||||
|
birthRemark: z.enum(['lahir_hidup', 'lahir_mati']).optional(),
|
||||||
|
})
|
||||||
|
|
||||||
|
const BloodInputSchema = z
|
||||||
|
.object({
|
||||||
|
type: z.enum(['prc', 'wb', 'ffp', 'tc']),
|
||||||
|
amount: z.object({
|
||||||
|
prc: z.coerce.number().optional(),
|
||||||
|
wb: z.coerce.number().optional(),
|
||||||
|
ffp: z.coerce.number().optional(),
|
||||||
|
tc: z.coerce.number().optional(),
|
||||||
|
}),
|
||||||
|
})
|
||||||
|
.transform((val) => ({
|
||||||
|
type: val.type,
|
||||||
|
amount: Object.fromEntries(
|
||||||
|
['prc', 'wb', 'ffp', 'tc'].map((k) => [k, val.type === k ? (val.amount[k] ?? null) : null]),
|
||||||
|
),
|
||||||
|
}))
|
||||||
|
|
||||||
|
const ImplantSchema = z.object({
|
||||||
|
brand: z.string().optional(),
|
||||||
|
name: z.string().optional(),
|
||||||
|
stickerNumber: z.string().optional(),
|
||||||
|
companionName: z.string().optional(),
|
||||||
|
})
|
||||||
|
|
||||||
|
const SpecimenSchema = z.object({
|
||||||
|
destination: z.string({
|
||||||
|
required_error: 'Silahkan pilih specimen',
|
||||||
|
}),
|
||||||
|
})
|
||||||
|
|
||||||
|
const TissueNoteSchema = z.object({
|
||||||
|
note: z
|
||||||
|
.string()
|
||||||
|
.trim()
|
||||||
|
.transform((val) => (val === '' ? undefined : val))
|
||||||
|
.optional(),
|
||||||
|
})
|
||||||
|
|
||||||
|
export const ActionReportSchema = z.object({
|
||||||
|
operatorTeam: OperatorTeamSchema,
|
||||||
|
procedures: z.array(ProcedureSchema).min(1, { message: 'Silahkan pilih prosedur' }),
|
||||||
|
|
||||||
|
operationExecution: OperationExecutionSchema,
|
||||||
|
|
||||||
|
bloodInput: BloodInputSchema.optional(),
|
||||||
|
implant: ImplantSchema.optional(),
|
||||||
|
specimen: SpecimenSchema.optional(),
|
||||||
|
|
||||||
|
tissueNotes: z.array(TissueNoteSchema).optional(),
|
||||||
|
})
|
||||||
|
|
||||||
|
export type ActionReportFormData = z.infer<typeof ActionReportSchema>
|
||||||
@@ -1,83 +0,0 @@
|
|||||||
import * as z from 'zod'
|
|
||||||
import { genEduAssessmentRaw, type EduAssessment, type EduAssessmentRaw } from '../models/edu-assessment'
|
|
||||||
import { serializeKeyToBoolean } from '../lib/clinical.constants'
|
|
||||||
|
|
||||||
const AssessmentEducationSchema = z.object({
|
|
||||||
generalEducationNeeds: z
|
|
||||||
.array(z.string(), {
|
|
||||||
required_error: 'Mohon pilih setidaknya item',
|
|
||||||
})
|
|
||||||
.min(1, 'Mohon pilih setidaknya item'),
|
|
||||||
|
|
||||||
specificEducationNeeds: z
|
|
||||||
.array(z.string(), {
|
|
||||||
required_error: 'Mohon pilih setidaknya item',
|
|
||||||
})
|
|
||||||
.min(1, 'Mohon pilih setidaknya item'),
|
|
||||||
|
|
||||||
learningAbility: z.string({
|
|
||||||
required_error: 'Mohon pilih kemampuan belajar',
|
|
||||||
}),
|
|
||||||
|
|
||||||
learningWillingness: z.string({
|
|
||||||
required_error: 'Mohon pilih kemauan belajar',
|
|
||||||
}),
|
|
||||||
|
|
||||||
barrier: z.string({
|
|
||||||
required_error: 'Mohon pilih hambatan',
|
|
||||||
}),
|
|
||||||
|
|
||||||
learningMethod: z.string({
|
|
||||||
required_error: 'Mohon pilih metode pembelajaran',
|
|
||||||
}),
|
|
||||||
|
|
||||||
language: z.string({
|
|
||||||
required_error: 'Mohon pilih bahasa',
|
|
||||||
}),
|
|
||||||
|
|
||||||
languageBarrier: z.string({
|
|
||||||
required_error: 'Mohon pilih hambatan bahasa',
|
|
||||||
}),
|
|
||||||
|
|
||||||
beliefValue: z.string({
|
|
||||||
required_error: 'Mohon pilih keyakinan pada nilai-nilai yang dianut',
|
|
||||||
}),
|
|
||||||
|
|
||||||
plans: z
|
|
||||||
.array(
|
|
||||||
z.object({
|
|
||||||
id: z.number(),
|
|
||||||
value: z.string().nonempty('Mohon masukkan catatan'),
|
|
||||||
}),
|
|
||||||
)
|
|
||||||
.min(1, 'Minimal 1 catatan rencana studi'),
|
|
||||||
})
|
|
||||||
|
|
||||||
type AssessmentEducationFormData = z.infer<typeof AssessmentEducationSchema>
|
|
||||||
|
|
||||||
export { AssessmentEducationSchema }
|
|
||||||
export type { AssessmentEducationFormData }
|
|
||||||
|
|
||||||
export function encode(encounterId: number, formData: AssessmentEducationFormData): EduAssessmentRaw {
|
|
||||||
let base = genEduAssessmentRaw()
|
|
||||||
// serialize general data
|
|
||||||
const general = serializeKeyToBoolean('general', formData.generalEducationNeeds)
|
|
||||||
const special = serializeKeyToBoolean('special', formData.specificEducationNeeds)
|
|
||||||
|
|
||||||
base.encounter_id = encounterId
|
|
||||||
base.generalEdus = JSON.stringify(general)
|
|
||||||
base.specialEdus = JSON.stringify(special)
|
|
||||||
|
|
||||||
base.assessments = JSON.stringify({
|
|
||||||
'learn-ability': formData.learningAbility,
|
|
||||||
'learn-will': formData.learningWillingness,
|
|
||||||
obstacle: formData.barrier,
|
|
||||||
'learn-method': formData.learningMethod,
|
|
||||||
lang: formData.language,
|
|
||||||
'lang-obstacle': formData.languageBarrier,
|
|
||||||
belief: formData.beliefValue,
|
|
||||||
})
|
|
||||||
|
|
||||||
base.plan = JSON.stringify(formData.plans)
|
|
||||||
return base
|
|
||||||
}
|
|
||||||
@@ -4,9 +4,8 @@ import { InternalReferenceSchema } from './internal-reference.schema'
|
|||||||
// Check In
|
// Check In
|
||||||
const CheckInSchema = z.object({
|
const CheckInSchema = z.object({
|
||||||
// registeredAt: z.string({ required_error: 'Tanggal masuk harus diisi' }),
|
// registeredAt: z.string({ required_error: 'Tanggal masuk harus diisi' }),
|
||||||
responsible_doctor_code: z.string({ required_error: 'Dokter harus diisi' }),
|
responsible_doctor_id: z.number({ required_error: 'Dokter harus diisi' }).gt(0, 'Dokter harus diisi'),
|
||||||
// adm_employee_id: z.number({ required_error: 'PJA harus diisi' }).gt(0, 'PJA harus diisi'),
|
adm_employee_id: z.number({ required_error: 'PJA harus diisi' }).gt(0, 'PJA harus diisi'),
|
||||||
registeredAt: z.string({ required_error: 'waktu harus diisi' }),
|
|
||||||
})
|
})
|
||||||
type CheckInFormData = z.infer<typeof CheckInSchema>
|
type CheckInFormData = z.infer<typeof CheckInSchema>
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user