Feat: Add & integrate add, edit, detail page

This commit is contained in:
hasyim_kai
2025-11-05 13:19:07 +07:00
parent 331f4a6b20
commit a361922e32
15 changed files with 475 additions and 211 deletions
@@ -32,25 +32,30 @@ const {
const doctors = ref<Array<Item>>([])
async function fetchDpjp() {
async function fetchDpjp(specialistId: string, subspecialistId: string) {
doctors.value = await getDoctorLabelList({
serviceType: 1,
serviceDate: new Date().toISOString().substring(0, 10),
specialistCode: 0,
includes: 'employee-person',
// "unit-id": parseInt(unitId),
"specialist-id": parseInt(specialistId),
"subspecialist-id": parseInt(subspecialistId),
})
}
const selectedDpjpId = inject<Ref<string | null>>("selectedDpjpId")!
function handleDpjpChange(selected: string) {
console.log(`change dphp`)
selectedDpjpId.value = selected ?? null
const dpjp = doctors.value.find(s => s.value === selectedDpjpId.value)
console.log(dpjp)
}
// const selectedUnitId = inject<Ref<string | null>>("selectedUnitId")!
const selectedSpecialistId = inject<Ref<string | null>>("selectedSpecialistId")!
const selectedSubSpecialistId = inject<Ref<string | null>>("selectedSubSpecialistId")!
onMounted(() => {
fetchDpjp()
// function handleDpjpChange(selected: string) {
// selectedDpjpId.value = selected ?? null
// }
watch([ selectedSpecialistId, selectedSubSpecialistId], () => {
if ( selectedSpecialistId.value && selectedSubSpecialistId.value) {
fetchDpjp( selectedSpecialistId.value, selectedSubSpecialistId.value)
}
})
</script>
@@ -82,7 +87,7 @@ onMounted(() => {
:placeholder="placeholder"
search-placeholder="Cari..."
empty-message="Data tidak ditemukan"
@update:model-value="handleDpjpChange"
:is-disabled="selectedSubSpecialistId === null"
/>
</FormControl>
<FormMessage />
@@ -10,8 +10,7 @@ import { getValueLabelList as getSubspecialistLabelList } from '~/services/subsp
import * as DE from '~/components/pub/my-ui/doc-entry'
const props = defineProps<{
specialistFieldName?: string
subSpecialistFieldName?: string
fieldName?: string
label?: string
placeholder?: string
errors?: FormErrors
@@ -23,8 +22,7 @@ const props = defineProps<{
}>()
const {
specialistFieldName = 'job',
subSpecialistFieldName = 'job',
fieldName = 'job',
label = 'Pekerjaan',
placeholder = 'Pilih pekerjaan',
errors,
@@ -34,96 +32,62 @@ const {
} = props
const specialists = ref<Array<Item>>([])
const subspecialists = ref<Array<Item>>([])
async function fetchSpecialists() {
async function fetchSpecialists(unitId: string) {
specialists.value = await getSpecialistLabelList({
serviceType: 1,
serviceDate: new Date().toISOString().substring(0, 10),
specialistCode: 0,
})
subspecialists.value = await getSubspecialistLabelList({
serviceType: 1,
serviceDate: new Date().toISOString().substring(0, 10),
specialistCode: 0,
"unit-id": parseInt(unitId),
})
}
const selectedUnitId = inject<Ref<string | null>>("selectedUnitId")!
const selectedSpecialistId = inject<Ref<string | null>>("selectedSpecialistId")!
function handleSpecialistChange(selected: string) {
selectedSpecialistId.value = selected ?? null
}
onMounted(() => {
fetchSpecialists()
watch([selectedUnitId], () => {
if (selectedUnitId.value) {
fetchSpecialists(selectedUnitId.value)
}
})
console.log(selectedUnitId.value)
</script>
<template>
<DE.Block :col-count="2" :class="cn('select-field-group', fieldGroupClass, containerClass)">
<DE.Block :class="cn('select-field-group', fieldGroupClass, containerClass)">
<div>
<DE.Label
:label-for="specialistFieldName"
:label-for="fieldName"
:class="cn('select-field-label', labelClass)"
:is-required="isRequired"
>
Spesialis
</DE.Label>
<DE.Field
:id="specialistFieldName"
:id="fieldName"
:errors="errors"
:class="cn('select-field-wrapper')"
>
<FormField
v-slot="{ componentField }"
:name="specialistFieldName"
:name="fieldName"
>
<FormItem>
<FormControl>
<Combobox
class="focus:ring-0 focus:ring-offset-0"
:id="specialistFieldName"
:id="fieldName"
v-bind="componentField"
:items="specialists"
:placeholder="placeholder"
search-placeholder="Cari..."
empty-message="Data tidak ditemukan"
@update:model-value="handleSpecialistChange"
/>
</FormControl>
<FormMessage />
</FormItem>
</FormField>
</DE.Field>
</div>
<div>
<DE.Label
:label-for="subSpecialistFieldName"
:class="cn('select-field-label', labelClass)"
:is-required="isRequired"
>
Sub Spesialis
</DE.Label>
<DE.Field
:id="subSpecialistFieldName"
:errors="errors"
:class="cn('select-field-wrapper')"
>
<FormField
v-slot="{ componentField }"
:name="subSpecialistFieldName"
>
<FormItem>
<FormControl>
<Combobox
class="focus:ring-0 focus:ring-offset-0"
:id="subSpecialistFieldName"
v-bind="componentField"
:items="subspecialists"
:placeholder="placeholder"
search-placeholder="Cari..."
empty-message="Data tidak ditemukan"
:is-disabled="!selectedSpecialistId"
:is-disabled="selectedUnitId === null"
/>
</FormControl>
<FormMessage />
@@ -0,0 +1,97 @@
<script setup lang="ts">
import type { FormErrors } from '~/types/error'
import Combobox from '~/components/pub/my-ui/combobox/combobox.vue'
import { cn, mapToComboboxOptList } from '~/lib/utils'
import { occupationCodes } from '~/lib/constants'
import type { Item } from '~/components/pub/my-ui/combobox'
import { getValueLabelList as getSubspecialistLabelList } from '~/services/subspecialist.service'
import * as DE from '~/components/pub/my-ui/doc-entry'
const props = defineProps<{
fieldName?: string
label?: string
placeholder?: string
errors?: FormErrors
class?: string
selectClass?: string
fieldGroupClass?: string
labelClass?: string
isRequired?: boolean
}>()
const {
fieldName = 'job',
label = 'Pekerjaan',
placeholder = 'Pilih pekerjaan',
errors,
class: containerClass,
fieldGroupClass,
labelClass,
} = props
const subspecialists = ref<Array<Item>>([])
async function fetchSubSpecialists(specialistId: string) {
subspecialists.value = await getSubspecialistLabelList({
serviceType: 1,
serviceDate: new Date().toISOString().substring(0, 10),
specialistCode: 0,
"specialist-id": parseInt(specialistId),
})
}
const selectedSpecialistId = inject<Ref<string | null>>("selectedSpecialistId")!
const selectedSubSpecialistId = inject<Ref<string | null>>("selectedSubSpecialistId")!
function handleSubSpecialistChange(selected: string) {
selectedSubSpecialistId.value = selected ?? null
}
watch([selectedSpecialistId], () => {
if (selectedSpecialistId.value) {
fetchSubSpecialists(selectedSpecialistId.value)
}
})
</script>
<template>
<DE.Block :class="cn('select-field-group', fieldGroupClass, containerClass)">
<div>
<DE.Label
:label-for="fieldName"
:class="cn('select-field-label', labelClass)"
:is-required="isRequired"
>
Sub Spesialis
</DE.Label>
<DE.Field
:id="fieldName"
:errors="errors"
:class="cn('select-field-wrapper')"
>
<FormField
v-slot="{ componentField }"
:name="fieldName"
>
<FormItem>
<FormControl>
<Combobox
class="focus:ring-0 focus:ring-offset-0"
:id="fieldName"
v-bind="componentField"
:items="subspecialists"
:placeholder="placeholder"
search-placeholder="Cari..."
empty-message="Data tidak ditemukan"
@update:model-value="handleSubSpecialistChange"
:is-disabled="selectedSpecialistId === null"
/>
</FormControl>
<FormMessage />
</FormItem>
</FormField>
</DE.Field>
</div>
</DE.Block>
</template>
@@ -0,0 +1,85 @@
<script setup lang="ts">
import type { FormErrors } from '~/types/error'
import Combobox from '~/components/pub/my-ui/combobox/combobox.vue'
import { cn, mapToComboboxOptList } from '~/lib/utils'
import { occupationCodes } from '~/lib/constants'
import { getValueLabelList as getUnitLabelList } from '~/services/unit.service'
import * as DE from '~/components/pub/my-ui/doc-entry'
import type { Item } from '~/components/pub/my-ui/combobox'
const props = defineProps<{
fieldName?: string
label?: string
placeholder?: string
errors?: FormErrors
class?: string
selectClass?: string
fieldGroupClass?: string
labelClass?: string
isRequired?: boolean
}>()
const {
fieldName = 'job',
label = 'Pekerjaan',
placeholder = 'Pilih pekerjaan',
errors,
class: containerClass,
fieldGroupClass,
labelClass,
} = props
const units = ref<Array<Item>>([])
async function fetchData() {
units.value = await getUnitLabelList()
}
const selectedUnitId = inject<Ref<string | null>>("selectedUnitId")!
function handleDataChange(selected: string) {
selectedUnitId.value = selected ?? null
}
onMounted(() => {
fetchData()
})
</script>
<template>
<DE.Cell :class="cn('select-field-group', fieldGroupClass, containerClass)">
<DE.Label
:label-for="fieldName"
:class="cn('select-field-label', labelClass)"
: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>
<Combobox
class="focus:ring-0 focus:ring-offset-0"
:id="fieldName"
v-bind="componentField"
:items="units"
:placeholder="placeholder"
search-placeholder="Cari..."
empty-message="Data tidak ditemukan"
@update:model-value="handleDataChange"
/>
</FormControl>
<FormMessage />
</FormItem>
</FormField>
</DE.Field>
</DE.Cell>
</template>
@@ -4,15 +4,22 @@ import { toTypedSchema } from '@vee-validate/zod'
import { Form } from '~/components/pub/ui/form'
import SelectDate from './_common/select-date.vue'
import InputBase from '~/components/pub/my-ui/form/input-base.vue'
import SelectSpeciality from './_common/select-speciality.vue'
import SelectSpeciality from './_common/select-specialist.vue'
import SelectDpjp from './_common/select-dpjp.vue'
import * as DE from '~/components/pub/my-ui/doc-entry'
import SelectUnit from './_common/select-unit.vue'
import SelectSubspecialist from './_common/select-subspecialist.vue'
import SelectSpecialist from './_common/select-specialist.vue'
const props = defineProps<{
schema: any
initialValues?: any
errors?: FormErrors
selectedUnitId?: number | null
selectedSpecialistId?: number | null
selectedSubSpecialistId?: number | null
}>()
const formSchema = toTypedSchema(props.schema)
@@ -50,21 +57,38 @@ defineExpose({
:errors="errors"
is-required
/>
<SelectSpeciality
specialist-field-name="spesialist_id"
sub-specialist-field-name="subspesialist_id"
label="Spesialis/Sub Spesialis"
placeholder="Pilih Spesialis/Sub Spesialis"
:errors="errors"
is-required
/>
<SelectDpjp
field-name="doctor_id"
label="DPJP"
placeholder="Pilih DPJP"
:errors="errors"
is-required
/>
<DE.Cell :col-span="2">
<DE.Block :col-count="4" :cell-flex="false">
<SelectUnit
field-name="unit_id"
label="Unit"
placeholder="Pilih Unit"
:errors="errors"
is-required
/>
<SelectSpecialist
field-name="specialist_id"
label="Spesialis/Sub Spesialis"
placeholder="Pilih Spesialis/Sub Spesialis"
:errors="errors"
is-required
/>
<SelectSubspecialist
field-name="subspecialist_id"
label="Spesialis/Sub Spesialis"
placeholder="Pilih Spesialis/Sub Spesialis"
:errors="errors"
is-required
/>
<SelectDpjp
field-name="doctor_id"
label="DPJP"
placeholder="Pilih DPJP"
:errors="errors"
is-required
/>
</DE.Block>
</DE.Cell>
</DE.Block>
</Form>
</template>
@@ -1,23 +1,11 @@
<script setup lang="ts">
import type { Patient } from '~/models/patient'
import DetailRow from '~/components/pub/my-ui/form/view/detail-row.vue'
import DetailSection from '~/components/pub/my-ui/form/view/detail-section.vue'
import { formatAddress } from '~/models/person-address'
import {
addressLocationTypeCode,
educationCodes,
genderCodes,
occupationCodes,
personContactTypes,
relationshipCodes,
religionCodes,
} from '~/lib/constants'
import { cn, mapToComboboxOptList } from '~/lib/utils'
import { cn, } from '~/lib/utils'
import type { ControlLetter } from '~/models/control-letter'
// #region Props & Emits
const props = defineProps<{
patient: Patient
instance: ControlLetter | null
}>()
const emit = defineEmits<{
@@ -27,39 +15,9 @@ const emit = defineEmits<{
// #endregion
// #region State & Computed
const genderOptions = mapToComboboxOptList(genderCodes)
const religionOptions = mapToComboboxOptList(religionCodes)
const educationOptions = mapToComboboxOptList(educationCodes)
const occupationOptions = mapToComboboxOptList(occupationCodes)
const relationshipOptions = mapToComboboxOptList(relationshipCodes)
const personContactTypeOptions = mapToComboboxOptList(personContactTypes)
// #endregion
// Computed addresses from nested data
const domicileAddress = computed(() => {
const addresses = props.patient.person.addresses
const resident = addresses?.find((addr) => addr.locationType_code === 'domicile')
return formatAddress(resident)
})
const identityAddress = computed(() => {
const addresses = props.patient.person.addresses
const primary = addresses?.find((addr) => addr.locationType_code === 'identity')
return formatAddress(primary)
})
const patientAge = computed(() => {
if (!props.patient.person.birthDate) {
return '-'
}
const birthDate = new Date(props.patient.person.birthDate)
const today = new Date()
let age = today.getFullYear() - birthDate.getFullYear()
const monthDiff = today.getMonth() - birthDate.getMonth()
if (monthDiff < 0 || (monthDiff === 0 && today.getDate() < birthDate.getDate())) {
age--
}
return age
})
// #endregion
// #region Lifecycle Hooks
@@ -81,10 +39,12 @@ function onClick(type: string) {
<template>
<div :class="cn('min-h-[50vh] space-y-2',)">
<DetailRow label="Tgl Rencana Kontrol">{{ patient.number || '-' }}</DetailRow>
<DetailRow label="Spesialis/Sub Spesialis">{{ patient.number || '-' }}</DetailRow>
<DetailRow label="DPJP">{{ patient.number || '-' }}</DetailRow>
<DetailRow label="Status SEP">{{ patient.number || '-' }}</DetailRow>
<DetailRow label="Tgl Rencana Kontrol">{{ props.instance?.date ? new Date(props.instance?.date).toLocaleDateString('id-ID') : '-' }}</DetailRow>
<DetailRow label="Unit">{{ props.instance?.unit.name || '-' }}</DetailRow>
<DetailRow label="Spesialis">{{ props.instance?.specialist.name || '-' }}</DetailRow>
<DetailRow label="Sub Spesialis">{{ props.instance?.subspecialist.name || '-' }}</DetailRow>
<DetailRow label="DPJP">{{ props.instance?.doctor.employee.person.name || '-' }}</DetailRow>
<DetailRow label="Status SEP">{{ 'SEP INTERNAL' }}</DetailRow>
</div>
<div class="border-t-1 my-2 flex justify-end border-t-slate-300 py-2">
<PubMyUiNavFooterBaEd @click="onClick" />
@@ -23,8 +23,10 @@ const controlLetterForm = ref<ExposedForm<any> | null>(null)
// #region State & Computed
const router = useRouter()
const isConfirmationOpen = ref(false)
const selectedUnitId = ref<number|null>(null)
const selectedSpecialistId = ref<number|null>(null)
const selectedDpjpId = ref<number|null>(null)
const selectedSubSpecialistId = ref<number|null>(null)
// #endregion
// #region Lifecycle Hooks
@@ -95,8 +97,9 @@ function handleCancelAdd() {
isConfirmationOpen.value = false
}
provide("selectedUnitId", selectedUnitId);
provide("selectedSpecialistId", selectedSpecialistId);
provide("selectedDpjpId", selectedDpjpId);
provide("selectedSubSpecialistId", selectedSubSpecialistId);
// #endregion
// #region Watchers
@@ -107,7 +110,11 @@ provide("selectedDpjpId", selectedDpjpId);
<div class="mb-5 border-b border-b-slate-300 pb-3 text-lg font-semibold xl:text-xl">Tambah Surat Kontrol</div>
<AppOutpatientEncounterEntryForm
ref="controlLetterForm"
:schema="ControlLetterSchema" />
:schema="ControlLetterSchema"
:selected-unit-id="selectedUnitId"
:selected-specialist-id="selectedSpecialistId"
:selected-sub-specialist-id="selectedSubSpecialistId"
/>
<div class="my-2 flex justify-end py-2">
<Action :enable-draft="false" @click="handleActionClick" />
@@ -8,24 +8,22 @@ import { getDetail } from '~/services/control-letter.service'
// Components
import Header from '~/components/pub/my-ui/nav-header/prep.vue'
import type { ControlLetter } from '~/models/control-letter'
// #region Props & Emits
const props = defineProps<{
patientId: number
}>()
// #endregion
// #region State & Computed
const route = useRoute()
const router = useRouter()
const patient = ref(
withBase<Patient>({
person: {} as Person,
personAddresses: [],
personContacts: [],
personRelatives: [],
}),
)
const encounterId = typeof route.params.id == 'string' ? parseInt(route.params.id) : 0
const controlLetterId = typeof route.params.control_letter_id == 'string' ? parseInt(route.params.control_letter_id) : 0
const controlLetter = ref<ControlLetter | null>(null)
const headerPrep: HeaderPrep = {
title: 'Detail Surat Kontrol',
@@ -36,10 +34,9 @@ const headerPrep: HeaderPrep = {
// #region Lifecycle Hooks
onMounted(async () => {
// await getPatientDetail()
const result = await getPatientDetail(props.patientId)
const result = await getDetail(controlLetterId)
if (result.success) {
patient.value = result.body.data || {}
controlLetter.value = result.body?.data
}
})
// #endregion
@@ -56,7 +53,10 @@ function handleAction(type: string) {
switch (type) {
case 'edit':
// TODO: Handle edit action
console.log('outpatient-encounter-id-edit')
navigateTo({
name: 'rehab-encounter-id-control-letter-control_letter_id-edit',
params: { id: encounterId, "control_letter_id": controlLetterId },
})
break
case 'cancel':
@@ -73,5 +73,5 @@ function handleAction(type: string) {
<template>
<Header :prep="headerPrep" :ref-search-nav="headerPrep.refSearchNav" />
<AppOutpatientEncounterPreview :patient="patient" @click="handleAction" />
<AppOutpatientEncounterPreview :instance="controlLetter" @click="handleAction" />
</template>
@@ -22,45 +22,51 @@ import {
isRecordConfirmationOpen,
onResetState,
handleActionSave,
handleCancelForm,
} from '~/handlers/patient.handler'
handleActionEdit,
} from '~/handlers/control-letter.handler'
import { toast } from '~/components/pub/ui/toast'
import { getPatientDetail } from '~/services/patient.service'
import { withBase } from '~/models/_base'
import type { Person } from '~/models/person'
import Confirmation from '~/components/pub/my-ui/confirmation/confirmation.vue'
import type { ControlLetter } from '~/models/control-letter'
import { ControlLetterSchema } from '~/schemas/control-letter.schema'
import { formatDateYyyyMmDd } from '~/lib/date'
// #region Props & Emits
const props = defineProps<{
callbackUrl?: string
patientId: number
}>()
// form related state
const personPatientForm = ref<ExposedForm<any> | null>(null)
const controlLetterForm = ref<ExposedForm<any> | null>(null)
// #endregion
// #region State & Computed
const route = useRoute()
const router = useRouter()
const encounterId = typeof route.params.id == 'string' ? parseInt(route.params.id) : 0
const controlLetterId = typeof route.params.control_letter_id == 'string' ? parseInt(route.params.control_letter_id) : 0
const isConfirmationOpen = ref(false)
const patient = ref(
withBase<Patient>({
person: {} as Person,
personAddresses: [],
personContacts: [],
personRelatives: [],
}),
)
const controlLetter = ref({})
const selectedUnitId = ref<number|null>(null)
const selectedSpecialistId = ref<number|null>(null)
const selectedSubSpecialistId = ref<number|null>(null)
// #endregion
// #region Lifecycle Hooks
onMounted(async () => {
// await getPatientDetail()
const result = await getPatientDetail(props.patientId)
const result = await getDetail(controlLetterId)
if (result.success) {
patient.value = result.body.data || {}
const responseData = {...result.body.data, date: formatDateYyyyMmDd(result.body.data.date)}
selectedUnitId.value = responseData?.unit_id
selectedSpecialistId.value = responseData?.specialist_id
selectedSubSpecialistId.value = responseData?.subspecialist_id
controlLetter.value = responseData
controlLetterForm.value?.setValues(responseData)
}
})
// #endregion
@@ -71,12 +77,30 @@ function goBack() {
}
async function handleConfirmAdd() {
// handleActionClick('submit')
console.log(`tersubmit wak`)
const response = await handleActionEdit(
controlLetterId,
await composeFormData(),
() => { },
() => { },
toast,
)
goBack()
}
function handleCancelAdd() {
isConfirmationOpen.value = false
async function composeFormData(): Promise<ControlLetter> {
const [controlLetter,] = await Promise.all([
controlLetterForm.value?.validate(),
])
const results = [controlLetter]
const allValid = results.every((r) => r?.valid)
// exit, if form errors happend during validation
if (!allValid) return Promise.reject('Form validation failed')
const formData = controlLetter?.values
formData.encounter_id = encounterId
return new Promise((resolve) => resolve(formData))
}
// #endregion region
@@ -84,29 +108,6 @@ function handleCancelAdd() {
async function handleActionClick(eventType: string) {
if (eventType === 'submit') {
isConfirmationOpen.value = true
// const patient: Patient = await composeFormData()
// let createdPatientId = 0
// const response = await handleActionSave(
// patient,
// () => {},
// () => {},
// toast,
// )
// const data = (response?.body?.data ?? null) as PatientBase | null
// if (!data) return
// createdPatientId = data.id
// // If has callback provided redirect to callback with patientData
// if (props.callbackUrl) {
// await navigateTo(props.callbackUrl + '?patient-id=' + patient.id)
// return
// }
// // Navigate to patient list or show success message
// await navigateTo('/outpatient/encounter')
// return
}
if (eventType === 'cancel') {
@@ -116,9 +117,16 @@ async function handleActionClick(eventType: string) {
}
goBack()
// handleCancelForm()
}
}
function handleCancelAdd() {
isConfirmationOpen.value = false
}
provide("selectedUnitId", selectedUnitId);
provide("selectedSpecialistId", selectedSpecialistId);
provide("selectedSubSpecialistId", selectedSubSpecialistId);
// #endregion
// #region Watchers
@@ -128,8 +136,11 @@ async function handleActionClick(eventType: string) {
<template>
<div class="mb-5 border-b border-b-slate-300 pb-3 text-lg font-semibold xl:text-xl">Update Surat Kontrol</div>
<AppOutpatientEncounterEntryForm
ref="personPatientForm"
:schema="PatientSchema"
ref="controlLetterForm"
:schema="ControlLetterSchema"
:selected-unit-id="selectedUnitId"
:selected-specialist-id="selectedSpecialistId"
:selected-sub-specialist-id="selectedSubSpecialistId"
/>
<div class="my-2 flex justify-end py-2">
@@ -107,8 +107,8 @@ watch([recId, recAction], () => {
switch (recAction.value) {
case ActionEvents.showDetail:
navigateTo({
name: 'outpatient-encounter-id',
params: { id: recId.value },
name: 'rehab-encounter-id-control-letter-control_letter_id',
params: { id: encounterId, "control_letter_id": recId.value },
})
break
@@ -116,8 +116,8 @@ watch([recId, recAction], () => {
// TODO: Handle edit action
// isFormEntryDialogOpen.value = true
navigateTo({
name: 'outpatient-encounter-id-edit',
params: { id: recId.value },
name: 'rehab-encounter-id-control-letter-control_letter_id-edit',
params: { id: encounterId, "control_letter_id": recId.value },
})
break
+8
View File
@@ -41,4 +41,12 @@ export function getAge(dateString: string, comparedDate?: string): { idFormat: s
idFormat,
extFormat
};
}
export function formatDateYyyyMmDd(isoDateString: string): string {
const date = new Date(isoDateString);
const year = date.getFullYear();
const month = String(date.getMonth() + 1).padStart(2, '0');
const day = String(date.getDate()).padStart(2, '0');
return `${year}-${month}-${day}`;
}
+27 -8
View File
@@ -1,18 +1,37 @@
import { type Base, genBase } from "./_base"
import { genDoctor, type Doctor } from "./doctor"
import { genEncounter, type Encounter } from "./encounter"
import { genSpecialist, type Specialist } from "./specialist"
import { genSubspecialist, type Subspecialist } from "./subspecialist"
import { genUnit, type Unit } from "./unit"
export interface ControlLetter extends Base {
sep_status: string
control_plan_date: string
specialist_sub_specialist_id: string
dpjp_id: string
encounter_id: number
encounter: Encounter
unit_id: number
unit: Unit
specialist_id: number
specialist: Specialist
subspecialist_id: number
subspecialist: Subspecialist
doctor_id: number
doctor: Doctor
date: ''
}
export function genControlLetter(): ControlLetter {
return {
...genBase(),
sep_status: '',
control_plan_date: '',
specialist_sub_specialist_id: '',
dpjp_id: '',
encounter_id: 0,
encounter: genEncounter(),
unit_id: 0,
unit: genUnit(),
specialist_id: 0,
specialist: genSpecialist(),
subspecialist_id: 0,
subspecialist: genSubspecialist(),
doctor_id: 0,
doctor: genDoctor(),
date: ''
}
}
@@ -0,0 +1,41 @@
<script setup lang="ts">
import type { PagePermission } from '~/models/role'
import Error from '~/components/pub/my-ui/error/error.vue'
import { PAGE_PERMISSIONS } from '~/lib/page-permission'
definePageMeta({
middleware: ['rbac'],
roles: ['doctor', 'nurse', 'admisi', 'pharmacy', 'billing', 'management'],
title: 'Update Surat Kontrol',
contentFrame: 'cf-full-width',
})
const route = useRoute()
useHead({
title: () => route.meta.title as string,
})
const roleAccess: PagePermission = PAGE_PERMISSIONS['/patient']
const { checkRole, hasReadAccess } = useRBAC()
// Check if user has access to this page
const hasAccess = checkRole(roleAccess)
// if (!hasAccess) {
// navigateTo('/403')
// }
// Define permission-based computed properties
// const canRead = hasReadAccess(roleAccess)
const canRead = true
</script>
<template>
<div>
<div v-if="canRead">
<ContentOutpatientEncounterEdit />
</div>
<Error v-else :status-code="403" />
</div>
</template>
@@ -0,0 +1,41 @@
<script setup lang="ts">
import type { PagePermission } from '~/models/role'
import Error from '~/components/pub/my-ui/error/error.vue'
import { PAGE_PERMISSIONS } from '~/lib/page-permission'
definePageMeta({
middleware: ['rbac'],
roles: ['doctor', 'nurse', 'admisi', 'pharmacy', 'billing', 'management'],
title: 'Detail Surat Kontrol',
contentFrame: 'cf-container-md',
})
const route = useRoute()
useHead({
title: () => route.meta.title as string,
})
const roleAccess: PagePermission = PAGE_PERMISSIONS['/patient']
const { checkRole, hasReadAccess } = useRBAC()
// Check if user has access to this page
const hasAccess = checkRole(roleAccess)
// if (!hasAccess) {
// navigateTo('/403')
// }
// Define permission-based computed properties
// const canRead = hasReadAccess(roleAccess)
const canRead = true
</script>
<template>
<div>
<div v-if="canRead">
<ContentOutpatientEncounterDetail :patient-id="Number(route.params.id)" />
</div>
<Error v-else :status-code="403" />
</div>
</template>
+7 -5
View File
@@ -4,17 +4,19 @@ const ControlLetterSchema = z.object({
sepStatus: z.string({
required_error: 'Mohon isi status SEP',
}).default('SEP Internal'),
spesialist_id: z.number({
required_error: 'Mohon isi Spesialis/Sub Spesialis',
unit_id: z.number({
required_error: 'Mohon isi Unit',
}),
subspesialist_id: z.number({
required_error: 'Mohon isi Spesialis/Sub Spesialis',
specialist_id: z.number({
required_error: 'Mohon isi Spesialis',
}),
subspecialist_id: z.number({
required_error: 'Mohon isi Sub Spesialis',
}),
doctor_id: z.number({
required_error: 'Mohon isi DPJP',
}),
encounter_id: z.number().optional(),
unit_id: z.number().optional(),
date: z.string({
required_error: 'Mohon lengkapi Tanggal Kontrol',
})