Fix: refactor rehab medik - Resume UI

This commit is contained in:
hasyim_kai
2025-11-07 08:55:23 +07:00
parent fc308809b8
commit 53bd8e7f6e
32 changed files with 2142 additions and 185 deletions
@@ -0,0 +1,22 @@
<script setup lang="ts">
import type { ListItemDto } from '~/components/pub/my-ui/data/types';
const props = defineProps<{
url: string
btnTxt?: string
rec: ListItemDto
}>()
function handlePrint() {
navigateTo(props.url || 'https://google.com', {external: true,open: { target: "_blank" },});
}
</script>
<template>
<Button
class="gap-3 items-center border-orange-400 text-orange-400"
variant="outline" @click="handlePrint">
<Icon name="i-lucide-printer" class="h-4 w-4" />
{{ props.btnTxt || 'Lampiran' }}
</Button>
</template>
@@ -0,0 +1,70 @@
<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 * 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
// Generate job options from constants, sama seperti pola genderCodes
const jobOptions = mapToComboboxOptList(occupationCodes)
</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="jobOptions"
:placeholder="placeholder"
search-placeholder="Cari..."
empty-message="Data tidak ditemukan"
/>
</FormControl>
<FormMessage />
</FormItem>
</FormField>
</DE.Field>
</DE.Cell>
</template>
@@ -0,0 +1,70 @@
<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 * 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
// Generate job options from constants, sama seperti pola genderCodes
const jobOptions = mapToComboboxOptList(occupationCodes)
</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="jobOptions"
:placeholder="placeholder"
search-placeholder="Cari..."
empty-message="Data tidak ditemukan"
/>
</FormControl>
<FormMessage />
</FormItem>
</FormField>
</DE.Field>
</DE.Cell>
</template>
@@ -0,0 +1,70 @@
<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 * 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
// Generate job options from constants, sama seperti pola genderCodes
const jobOptions = mapToComboboxOptList(occupationCodes)
</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="jobOptions"
:placeholder="placeholder"
search-placeholder="Cari..."
empty-message="Data tidak ditemukan"
/>
</FormControl>
<FormMessage />
</FormItem>
</FormField>
</DE.Field>
</DE.Cell>
</template>
@@ -0,0 +1,70 @@
<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 * 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
// Generate job options from constants, sama seperti pola genderCodes
const jobOptions = mapToComboboxOptList(occupationCodes)
</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="jobOptions"
:placeholder="placeholder"
search-placeholder="Cari..."
empty-message="Data tidak ditemukan"
/>
</FormControl>
<FormMessage />
</FormItem>
</FormField>
</DE.Field>
</DE.Cell>
</template>
@@ -0,0 +1,70 @@
<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 * 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
// Generate job options from constants, sama seperti pola genderCodes
const jobOptions = mapToComboboxOptList(occupationCodes)
</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="jobOptions"
:placeholder="placeholder"
search-placeholder="Cari..."
empty-message="Data tidak ditemukan"
/>
</FormControl>
<FormMessage />
</FormItem>
</FormField>
</DE.Field>
</DE.Cell>
</template>
@@ -0,0 +1,70 @@
<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 * 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
// Generate job options from constants, sama seperti pola genderCodes
const jobOptions = mapToComboboxOptList(occupationCodes)
</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="jobOptions"
:placeholder="placeholder"
search-placeholder="Cari..."
empty-message="Data tidak ditemukan"
/>
</FormControl>
<FormMessage />
</FormItem>
</FormField>
</DE.Field>
</DE.Cell>
</template>
@@ -0,0 +1,70 @@
<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 * 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
// Generate job options from constants, sama seperti pola genderCodes
const jobOptions = mapToComboboxOptList(occupationCodes)
</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="jobOptions"
:placeholder="placeholder"
search-placeholder="Cari..."
empty-message="Data tidak ditemukan"
/>
</FormControl>
<FormMessage />
</FormItem>
</FormField>
</DE.Field>
</DE.Cell>
</template>
@@ -0,0 +1,70 @@
<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 * 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
// Generate job options from constants, sama seperti pola genderCodes
const jobOptions = mapToComboboxOptList(occupationCodes)
</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="jobOptions"
:placeholder="placeholder"
search-placeholder="Cari..."
empty-message="Data tidak ditemukan"
/>
</FormControl>
<FormMessage />
</FormItem>
</FormField>
</DE.Field>
</DE.Cell>
</template>
@@ -0,0 +1,70 @@
<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 * 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
// Generate job options from constants, sama seperti pola genderCodes
const jobOptions = mapToComboboxOptList(occupationCodes)
</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="jobOptions"
:placeholder="placeholder"
search-placeholder="Cari..."
empty-message="Data tidak ditemukan"
/>
</FormControl>
<FormMessage />
</FormItem>
</FormField>
</DE.Field>
</DE.Cell>
</template>
@@ -0,0 +1,67 @@
<script setup lang="ts">
import { Badge, type Variants } from '~/components/pub/ui/badge'
const activeStatusCodes: Record<string, string> = {
verified: 'Terverifikasi',
validated: 'Tervalidasi',
unverified: 'Belum Verifikasi',
unvalidated: 'Batal Validasi',
}
const props = defineProps<{
rec: any
idx?: number
}>()
const statusText = computed(() => {
let code: keyof typeof activeStatusCodes = `unverified`
switch (props.rec.status_code) {
case 1:
code = 'verified'
break
case 2:
code = 'validated'
break
case 3:
code = 'unverified'
break
case 4:
code = 'unvalidated'
break
default:
code = 'unverified'
break
}
return activeStatusCodes[code]
})
const badgeVariant = computed(() => {
let variant: Variants = `outline`
switch (props.rec.status_code) {
case 1:
variant = 'secondary'
break
case 2:
variant = 'default'
break
case 3:
variant = 'outline'
break
case 4:
variant = 'destructive'
break
default:
variant = 'outline'
break
}
return variant
})
</script>
<template>
<div class="flex justify-center">
<Badge :variant="badgeVariant" class="rounded-2xl text-[0.6rem]" >
{{ statusText }}
</Badge>
</div>
</template>
+380 -88
View File
@@ -8,12 +8,19 @@ import InputBase from '~/components/pub/my-ui/form/input-base.vue'
import * as DE from '~/components/pub/my-ui/doc-entry'
import TextAreaInput from '~/components/pub/my-ui/form/text-area-input.vue'
import SelectSecondaryDiagnosis from './_common/select-secondary-diagnosis.vue'
import SelectPrimaryDiagnosis from './_common/select-primary-diagnosis.vue'
import SelectArrangement from './_common/select-arrangement.vue'
import type { ResumeArrangementType } from '~/schemas/resume.schema'
import SelectFaskes from './_common/select-faskes.vue'
import SelectDeathCause from './_common/select-death-cause.vue'
import SelectIcd10 from './_common/select-icd-10.vue'
import SelectIcd9 from './_common/select-icd-9.vue'
import SelectConciousLevel from './_common/select-concious-level.vue'
import SelectPainScale from './_common/select-pain-scale.vue'
import SelectNationalProgramService from './_common/select-national-program-service.vue'
import SelectNationalProgramServiceStatus from './_common/select-national-program-service-status.vue'
import SelectHospitalLeaveCondition from './_common/select-hospital-leave-condition.vue'
import SelectFollowingArrangement from './_common/select-following-arrangement.vue'
import SelectHospitalLeaveMethod from './_common/select-hospital-leave-method.vue'
const props = defineProps<{
schema: any
@@ -22,6 +29,11 @@ const props = defineProps<{
errors?: FormErrors
}>()
const isActionHistoryOpen = inject(`isActionHistoryOpen`) as Ref<boolean>
const isConsultationHistoryOpen = inject(`isConsultationHistoryOpen`) as Ref<boolean>
const isSupportingHistoryOpen = inject(`isSupportingHistoryOpen`) as Ref<boolean>
const isFarmacyHistoryOpen = inject(`isFarmacyHistoryOpen`) as Ref<boolean>
const isNationalProgramServiceHistoryOpen = inject(`isNationalProgramServiceHistoryOpen`) as Ref<boolean>
const formSchema = toTypedSchema(props.schema)
const formRef = ref()
@@ -31,101 +43,369 @@ defineExpose({
setValues: (values: any, shouldValidate = true) => formRef.value?.setValues(values, shouldValidate),
values: computed(() => formRef.value?.values),
})
const DEFAULT_SECONDARY_DIAGNOSIS_VALUE = {
diagnosis: '',
icd10: '',
diagnosisBasis: '',
};
const DEFAULT_SECONDARY_ACTION_VALUE = {
action: '',
icd9: '',
actionBasis: '',
};
const DEFAULT_CONSULTATION_VALUE = {
consultation: '',
consultationReply: '',
};
</script>
<template>
<Form ref="formRef" v-slot="{ values }" as="" keep-values :validation-schema="formSchema" :validate-on-mount="false"
validation-mode="onSubmit" :initial-values="initialValues ? initialValues : {}">
<Form ref="formRef"
v-slot="{ values }"
as=""
keep-values
:validation-schema="formSchema"
:validate-on-mount="false"
validation-mode="onSubmit"
:initial-values="initialValues ? initialValues : {}">
<!-- Pasien -->
<h1 class="mb-3 text-base font-medium">Pemeriksaan Pasien</h1>
<DE.Block :col-count="3" :cell-flex="false">
<SelectDate field-name="inDate" label="Tanggal Masuk" :errors="errors" :is-disabled="true" />
<SelectDate field-name="outDate" label="Tanggal Keluar" :errors="errors" :is-disabled="true" />
</DE.Block>
<SelectDate field-name="outDate" label="Tanggal Keluar" :errors="errors" :is-disabled="true" />
<InputBase
field-name="doctor_id"
:is-disabled="true"
label="DPJP" placeholder="DPJP"/>
</DE.Block>
<DE.Block class="" :cell-flex="false">
<InputBase
class="w-2/3"
field-name="first_diagnosis"
:is-disabled="true"
label="Diagnosis Masuk/Rujukan" placeholder="Diagnosis Masuk/Rujukan"/>
</DE.Block>
<DE.Block :col-count="3" :cell-flex="false">
<TextAreaInput field-name="anamnesis" label="Anamnesis" placeholder="Anamnesis" :errors="errors" />
<TextAreaInput field-name="physicalCheckup" label="Pemeriksaan Fisik" placeholder="Pemeriksaan Fisik"
:errors="errors" />
<TextAreaInput field-name="supplementCheckup" label="Pemeriksaan Penunjang" placeholder="Pemeriksaan Penunjang"
:errors="errors" />
<TextAreaInput field-name="supplementCheckup"
label="Indikasi Rawat Jalan" placeholder="Indikasi Rawat Jalan" :errors="errors" />
<TextAreaInput field-name="supplementCheckup"
label="Keluhan Utama (Singkat & Menunjang)" placeholder="Keluhan Utama (Singkat & Menunjang)" :errors="errors" />
<TextAreaInput field-name="supplementCheckup"
label="Pemeriksaan Fisik (Singkat & Menunjang)" placeholder="Pemeriksaan Fisik (Singkat & Menunjang)" :errors="errors" />
<TextAreaInput field-name="supplementCheckup"
label="Riwayat Penyakit" placeholder="Riwayat Penyakit" :errors="errors" />
<TextAreaInput field-name="supplementCheckup"
label="Diagnosa Medis" placeholder="Diagnosa Medis" :errors="errors" />
</DE.Block>
<Separator class="my-4" />
<!-- DIAGNOSIS -->
<h1 class="mb-3 text-base font-medium">Diagnosis</h1>
<DE.Block class="w-3/5 space-y-2" :cell-flex="false">
<SelectPrimaryDiagnosis
<h1 class="mb-3 text-base font-medium">Diagnosa</h1>
<h1 class="mb-3 text-base font-medium">Diagnosa Utama</h1>
<DE.Block :col-count="2" class="" :cell-flex="false">
<InputBase
field-name="diagnosis"
label="Diagnosa" placeholder="Masukkan Diagnosa"
:errors="errors" is-required />
<SelectIcd10
field-name="primaryDiagnosis"
label="Diagnosis Utama"
placeholder="Diagnosis Utama"
label="ICD 10"
placeholder="ICD 10"
:errors="errors" is-required />
<DE.Cell :col-span="2">
<TextAreaInput field-name="supplementCheckup"
label="Dasar Diagnosa" placeholder="Masukkan Dasar Diagnosa utama Pasien" :errors="errors" />
</DE.Cell>
<div class="w-full rounded-md border bg-gray-50/50 p-4 shadow-sm dark:bg-neutral-950">
<h1 class="mb-3 font-medium">Diagnosis Sekunder</h1>
<FieldArray v-slot="{ fields, push, remove }" name="secondaryDiagnosis">
<div v-for="(field, idx) in fields" :key="idx" class="flex items-center gap-3 mb-3">
<SelectSecondaryDiagnosis
:field-name="`secondaryDiagnosis[${idx}]`"
:errors="errors"
/>
<Button type="button" variant="destructive" size="sm" @click="remove(idx)">
<Icon name="i-lucide-trash-2" class="h-4 w-4" />
<DE.Cell :col-span="2">
<h1 class="mb-3 text-base font-medium">Diagnosa Sekunder</h1>
<div class="w-full rounded-md border bg-gray-50/50 p-4 shadow-sm dark:bg-neutral-950">
<FieldArray v-slot="{ fields, push, remove }" name="secondaryDiagnosis">
<div v-for="(field, idx) in fields" :key="idx" class="flex items-center gap-3 mb-3">
<div class="w-full">
<h1 class="font-medium">Diagnosa {{ idx + 1 }}</h1>
<div class="flex gap-3">
<InputBase
:field-name="`secondaryDiagnosis[${idx}].diagnosis`"
label="Diagnosa" placeholder="Masukkan Diagnosa"
:errors="errors" is-required />
<SelectIcd10
:field-name="`secondaryDiagnosis[${idx}].icd10`"
label="ICD 10"
placeholder="ICD 10"
:errors="errors" is-required />
</div>
<TextAreaInput :field-name="`secondaryDiagnosis[${idx}].diagnosisBasis`"
label="Dasar Diagnosa" placeholder="Masukkan Dasar Diagnosa Pasien" :errors="errors" />
</div>
<Button v-if="idx !== 0" type="button" variant="destructive" size="sm" @click="remove(idx)">
<Icon name="i-lucide-trash-2" class="h-4 w-4" />
</Button>
</div>
<Button type="button" variant="outline"
class="w-full rounded-md border border-primary bg-white px-4 py-2 text-primary hover:border-primary hover:bg-primary hover:text-white sm:w-auto sm:text-sm"
@click="push(DEFAULT_SECONDARY_DIAGNOSIS_VALUE)">
<Icon name="i-lucide-plus" class="mr-2 h-4 w-4 align-middle transition-colors" />
Tambah Diagnosis
</Button>
</div>
<Button type="button" variant="outline"
class="w-full rounded-md border border-primary bg-white px-4 py-2 text-primary hover:border-primary hover:bg-primary hover:text-white sm:w-auto sm:text-sm"
@click="push(``)">
<Icon name="i-lucide-plus" class="mr-2 h-4 w-4 align-middle transition-colors" />
Tambah Diagnosis
</Button>
</FieldArray>
</div>
</DE.Block>
<Separator class="my-4" />
</FieldArray>
</div>
</DE.Cell>
<!-- DIAGNOSIS -->
<h1 class="mb-3 text-base font-medium">Tindakan Operatif/Non Operatif</h1>
<DE.Block class="w-3/5 space-y-2" :cell-flex="false">
<SelectPrimaryDiagnosis
field-name="primaryOperativeNonOperativeAct"
label="Tindakan Operatif Utama"
placeholder="Tindakan Operatif Utama"
:errors="errors" is-required />
<div class="w-full rounded-md border bg-gray-50/50 p-4 shadow-sm dark:bg-neutral-950">
<h1 class="mb-3 font-medium">Tindakan / Prosedur</h1>
<FieldArray v-slot="{ fields, push, remove }" name="secondaryOperativeNonOperativeAct">
<div v-for="(field, idx) in fields" :key="idx" class="flex items-center gap-3 mb-3">
<SelectSecondaryDiagnosis
:field-name="`secondaryOperativeNonOperativeAct[${idx}]`"
:errors="errors"
/>
<Button type="button" variant="destructive" size="sm" @click="remove(idx)">
<Icon name="i-lucide-trash-2" class="h-4 w-4" />
</Button>
</div>
<Button type="button" variant="outline"
class="w-full rounded-md border border-primary bg-white px-4 py-2 text-primary hover:border-primary hover:bg-primary hover:text-white sm:w-auto sm:text-sm"
@click="push(``)">
<Icon name="i-lucide-plus" class="mr-2 h-4 w-4 align-middle transition-colors" />
Tambah Tindakan / Prosedur
</Button>
</FieldArray>
</div>
</DE.Block>
<Separator class="my-4" />
<DE.Block class="w-3/5" :cell-flex="false">
<TextAreaInput field-name="medikamentosa" label="Medikamentosa" placeholder="Medikamentosa" :errors="errors" />
</DE.Block>
<Separator class="my-4" />
<h1 class="mb-3 font-medium">Penatalaksanaan</h1>
<DE.Block :col-count="3" :cell-flex="false">
<SelectArrangement field-name="arrangement" label="Lanjutan Penatalaksanaan" placeholder="Pilih Arrangement" :errors="errors" />
</DE.Block>
<Separator class="my-4" />
<!-- Tindakan OPERATIF/NON OPERATIF -->
<div class="mb-3 flex gap-3 items-center">
<h1 class="text-base font-medium">Tindakan Operatif/Non Operatif</h1>
<Button variant="ghost"
class="gap-1 items-center text-orange-400"
@click="isActionHistoryOpen = true">
<Icon name="i-lucide-history" class="h-4 w-4" /> Riwayat Tindakan</Button>
</div>
<h1 class="mb-3 font-normal">Tindakan Operatif/Non Operatif Utama</h1>
<DE.Block :col-count="2" class="" :cell-flex="false">
<InputBase
field-name="diagnosis"
label="Tindakan" placeholder="Masukkan Tindakan"
:errors="errors" is-required />
<SelectIcd9
field-name="primaryDiagnosis"
label="ICD 9"
placeholder="ICD 9"
:errors="errors" is-required />
<DE.Cell :col-span="2">
<TextAreaInput field-name="supplementCheckup"
label="Dasar Tindakan" placeholder="Masukkan Dasar Tindakan utama Pasien" :errors="errors" />
</DE.Cell>
<DE.Cell :col-span="2">
<h1 class="mb-3 text-base font-medium">Tindakan Lain</h1>
<div class="w-full rounded-md border bg-gray-50/50 p-4 shadow-sm dark:bg-neutral-950">
<FieldArray v-slot="{ fields, push, remove }" name="secondaryOperativeNonOperativeAct">
<div v-for="(field, idx) in fields" :key="idx" class="flex items-center gap-3 mb-3">
<div class="w-full">
<h1 class="font-medium">Tindakan {{ idx + 1 }}</h1>
<div class="flex gap-3">
<InputBase
:field-name="`secondaryOperativeNonOperativeAct[${idx}].action`"
label="Tindakan" placeholder="Masukkan Tindakan"
:errors="errors" is-required />
<SelectIcd10
:field-name="`secondaryOperativeNonOperativeAct[${idx}].icd9`"
label="ICD 10"
placeholder="ICD 10"
:errors="errors" is-required />
</div>
<TextAreaInput :field-name="`secondaryOperativeNonOperativeAct[${idx}].actionBasis`"
label="Dasar Tindakan" placeholder="Masukkan Dasar Tindakan Pasien" :errors="errors" />
</div>
<Button v-if="idx !== 0" type="button" variant="destructive" size="sm" @click="remove(idx)">
<Icon name="i-lucide-trash-2" class="h-4 w-4" />
</Button>
</div>
<Button type="button" variant="outline"
class="w-full rounded-md border border-primary bg-white px-4 py-2 text-primary hover:border-primary hover:bg-primary hover:text-white sm:w-auto sm:text-sm"
@click="push(DEFAULT_SECONDARY_ACTION_VALUE)">
<Icon name="i-lucide-plus" class="mr-2 h-4 w-4 align-middle transition-colors" />
Tambah Tindakan
</Button>
</FieldArray>
</div>
</DE.Cell>
</DE.Block>
<TextAreaInput :field-name="`medicalAction`"
label="Tindakan Medis" placeholder="Masukkan Tindakan Medis" :errors="errors" />
<Separator class="my-4" />
<!-- KONSULTASI -->
<div class="mb-3 flex gap-3 items-center">
<h1 class="text-base font-medium">Konsultasi</h1>
<Button variant="ghost"
class="gap-1 items-center text-orange-400"
@click="isConsultationHistoryOpen = true">
<Icon name="i-lucide-history" class="h-4 w-4" /> Riwayat Konsultasi</Button>
</div>
<div class="w-full rounded-md border bg-gray-50/50 p-4 shadow-sm dark:bg-neutral-950">
<FieldArray v-slot="{ fields, push, remove }" name="consultation">
<div v-for="(field, idx) in fields" :key="idx" class="flex items-center gap-3 mb-3">
<div class="w-full">
<h1 class="font-medium mb-1">Konsultasi {{ idx + 1 }}</h1>
<div class="flex gap-3">
<TextAreaInput :field-name="`consultation[${idx}].consultation`"
label="Konsultasi" placeholder="Masukkan Konsultasi" :errors="errors" />
<TextAreaInput :field-name="`consultation[${idx}].consultationReply`"
label="Jawaban Konsultasi" placeholder="Masukkan Jawaban Konsultasi" :errors="errors" />
</div>
</div>
<Button v-if="idx !== 0" type="button" variant="destructive" size="sm" @click="remove(idx)">
<Icon name="i-lucide-trash-2" class="h-4 w-4" />
</Button>
</div>
<Button type="button" variant="outline"
class="w-full rounded-md border border-primary bg-white px-4 py-2 text-primary hover:border-primary hover:bg-primary hover:text-white sm:w-auto sm:text-sm"
@click="push(DEFAULT_CONSULTATION_VALUE)">
<Icon name="i-lucide-plus" class="mr-2 h-4 w-4 align-middle transition-colors" />
Tambah Konsultasi
</Button>
</FieldArray>
</div>
<Separator class="my-4" />
<!-- DATA PENUNJANG -->
<section>
<div class="mb-3 flex gap-3 items-center">
<h1 class="text-base font-medium">Data Penunjang</h1>
<Button variant="ghost"
class="gap-1 items-center text-orange-400"
@click="isSupportingHistoryOpen = true">
<Icon name="i-lucide-history" class="h-4 w-4" /> Riwayat Data Penunjang</Button>
</div>
<DE.Block class="" :cell-flex="false">
<TextAreaInput field-name="supplementCheckup" label="Pemeriksaan Penunjang" placeholder="Masukkan Pemeriksaan Penunjang" :errors="errors" />
</DE.Block>
</section>
<Separator class="my-4" />
<!-- DATA Farmasi -->
<section>
<div class="mb-3 flex gap-3 items-center">
<h1 class="text-base font-medium">Data Farmasi</h1>
<Button variant="ghost"
class="gap-1 items-center text-orange-400"
@click="isFarmacyHistoryOpen = true">
<Icon name="i-lucide-history" class="h-4 w-4" /> Riwayat Data Farmasi</Button>
</div>
<DE.Block class="items-end" :col-count="3" :cell-flex="false">
<TextAreaInput field-name="supplementCheckup"
label="Kelainan Khusus Alergi" placeholder="Masukkan Kelainan Khusus Alergi" :errors="errors" />
<TextAreaInput field-name="supplementCheckup"
label="Kelainan Lain" placeholder="Masukkan Kelainan Lain" :errors="errors" />
<TextAreaInput field-name="supplementCheckup"
label="Terapi yang Diberikan (Farmakologi dan Non Farmakologi) Selama Dirawat" placeholder="Masukkan Terapi yang Diberikan (Farmakologi dan Non Farmakologi) Selama Dirawat" :errors="errors" />
<TextAreaInput field-name="supplementCheckup"
label="Terapi yang Diberikan (Farmakologi dan Non Farmakologi) Waktu Pulang" placeholder="Masukkan Terapi yang Diberikan (Farmakologi dan Non Farmakologi) Waktu Pulang" :errors="errors" />
<TextAreaInput field-name="supplementCheckup"
label="Instruksi Tindak Lanjut/Anjuran dan Edukasi (Follow Up/Kontrol)" placeholder="Masukkan Instruksi Tindak Lanjut/Anjuran dan Edukasi (Follow Up/Kontrol)" :errors="errors" />
</DE.Block>
</section>
<Separator class="my-4" />
<!-- Keadaan Waktu Keluar -->
<section>
<h1 class="mb-3 font-medium">Keadaan Waktu Keluar</h1>
<DE.Block :col-count="4" :cell-flex="false">
<InputBase
:field-name="`aaaaaaaaaaa`"
label="Tekanan Darah Sistol" placeholder="Masukkan Tekanan Darah Sistol"
right-label="mmHg" bottom-label="Contoh: 90"
:errors="errors" is-required numeric-only />
<InputBase
:field-name="`aaaaaaaaaaa`"
label="Tekanan Darah Diastol" placeholder="Masukkan Tekanan Darah Diastol"
right-label="mmHg" bottom-label="Contoh: 60"
:errors="errors" is-required numeric-only />
<InputBase
:field-name="`aaaaaaaaaaa`"
label="Pernafasan" placeholder="Masukkan Pernafasan"
right-label="kali / menit" bottom-label="Contoh: 20"
:errors="errors" is-required numeric-only />
<InputBase
:field-name="`aaaaaaaaaaa`"
label="Denyut Jantung" placeholder="Masukkan Denyut Jantung"
right-label="kali / menit" bottom-label="Contoh: 20"
:errors="errors" is-required numeric-only />
<InputBase
:field-name="`aaaaaaaaaaa`"
label="Suhu Tubuh" placeholder="Masukkan Suhu Tubuh"
right-label="'C" bottom-label="Contoh: 37"
:errors="errors" is-required numeric-only />
<SelectConciousLevel
:field-name="`aaaaaaaaaaa`"
label="Tingkat Kesadaran"
placeholder="Tingkat Kesadaran"
:errors="errors" is-required />
<SelectPainScale
:field-name="`aaaaaaaaaaa`"
label="Skala Nyeri"
placeholder="Skala Nyeri"
:errors="errors" is-required />
</DE.Block>
</section>
<Separator class="my-4" />
<!-- Program Nasional -->
<section>
<div class="mb-3 flex gap-3 items-center">
<h1 class="text-base font-medium">Program Nasional</h1>
<Button variant="ghost"
class="gap-1 items-center text-orange-400"
@click="isNationalProgramServiceHistoryOpen = true">
<Icon name="i-lucide-history" class="h-4 w-4" /> Riwayat Program Nasional</Button>
</div>
<DE.Block :col-count="3" :cell-flex="false">
<SelectNationalProgramService
:field-name="`aaaaaaaaaaa`"
label="Layanan Program Nasional"
placeholder="Layanan Program Nasional"
:errors="errors" is-required />
<SelectNationalProgramServiceStatus
:field-name="`aaaaaaaaaaa`"
label="Status Layanan Program Nasional"
placeholder="Status Layanan Program Nasional"
:errors="errors" is-required />
</DE.Block>
</section>
<Separator class="my-4" />
<!-- Penatalaksanaan -->
<section>
<h1 class="mb-3 font-medium">Penatalaksanaan</h1>
<DE.Block :col-count="3" :cell-flex="false">
<SelectArrangement
field-name="arrangement"
label="Lanjutan Penatalaksanaan"
placeholder="Pilih Arrangement"
:errors="errors" />
<SelectHospitalLeaveCondition
:field-name="`aaaaaaaaaaa`"
label="Kondisi Meninggalkan RS"
placeholder="Kondisi Meninggalkan RS"
:errors="errors" is-required />
<SelectHospitalLeaveMethod
:field-name="`aaaaaaaaaaa`"
label="Cara Keluar RS"
placeholder="Cara Keluar RS"
:errors="errors" is-required />
</DE.Block>
</section>
<DE.Block :col-count="3" :cell-flex="false">
<SelectFaskes
v-show="resumeArrangementType === `rujuk` || resumeArrangementType === `rujukBalik` "
field-name="faskes"
@@ -148,8 +428,8 @@ defineExpose({
:errors="errors"
:is-with-time="true" />
<DE.Cell class="mt-2" :col-span="2" v-show="resumeArrangementType === `meninggal`">
<div class="w-full rounded-md border bg-gray-50/50 p-4 shadow-sm dark:bg-neutral-950">
<DE.Cell class="mt-2" :col-span="3" v-show="resumeArrangementType === `meninggal`">
<div class="w-2/3 rounded-md border bg-gray-50/50 p-4 shadow-sm dark:bg-neutral-950">
<h1 class="mb-3 font-medium">Sebab Meninggal</h1>
<FieldArray v-slot="{ fields, push, remove }" name="deathCause">
@@ -158,11 +438,11 @@ defineExpose({
:field-name="`deathCause[${idx}]`"
:errors="errors"
/>
<Button type="button" variant="destructive" size="sm" @click="remove(idx)">
<Button v-if="idx !== 0" type="button" variant="destructive" size="sm" @click="remove(idx)">
<Icon name="i-lucide-trash-2" class="h-4 w-4" />
</Button>
</div>
<Button type="button" variant="outline"
<Button v-if="fields.length < 3" type="button" variant="outline"
class="w-full rounded-md border border-primary bg-white px-4 py-2 text-primary hover:border-primary hover:bg-primary hover:text-white sm:w-auto sm:text-sm"
@click="push(``)">
<Icon name="i-lucide-plus" class="mr-2 h-4 w-4 align-middle transition-colors" />
@@ -172,12 +452,24 @@ defineExpose({
</div>
</DE.Cell>
<TextAreaInput
v-show="resumeArrangementType === `other`"
field-name="keterangan"
label="Keterangan"
placeholder="Keterangan"
:errors="errors" />
<DE.Cell
v-show="resumeArrangementType === `meninggal`"
:col-span="3">
<TextAreaInput
field-name="deathCauseDescription"
label="Keterangan Sebab Meninggal"
placeholder="Keterangan Sebab Meninggal"
:errors="errors" />
</DE.Cell>
<DE.Cell :col-span="3"
v-show="resumeArrangementType === `other`">
<TextAreaInput
field-name="keterangan"
label="Keterangan"
placeholder="Keterangan"
:errors="errors" />
</DE.Cell>
</DE.Block>
@@ -0,0 +1,66 @@
<script setup lang="ts">
import Dialog from '~/components/pub/my-ui/modal/dialog.vue'
import type { PaginationMeta } from '~/components/pub/my-ui/pagination/pagination.type'
import PaginationView from '~/components/pub/my-ui/pagination/pagination-view.vue'
import { config } from './action-list.cfg'
import { cn } from '~/lib/utils'
import { CalendarDate, DateFormatter, getLocalTimeZone } from '@internationalized/date'
import type { DateRange } from 'radix-vue'
import { CalendarIcon } from 'lucide-vue-next'
interface Props {
data: any[]
paginationMeta: PaginationMeta
dateValue: DateRange
}
const props = defineProps<Props>()
const isModalOpen = inject(`isActionHistoryOpen`) as Ref<boolean>
const df = new DateFormatter('en-US', { dateStyle: 'medium',})
const emit = defineEmits<{
pageChange: [page: number]
'update:dateValue': [value: DateRange]
}>()
function handlePageChange(page: number) {
emit('pageChange', page)
}
</script>
<template>
<Dialog v-model:open="isModalOpen" title="" size="2xl">
<div class="space-y-4">
<Popover>
<PopoverTrigger as-child>
<Button variant="outline" :class="cn('mb-1 w-[280px] justify-start text-left font-normal',
!props.dateValue && 'text-muted-foreground')">
<CalendarIcon class="mr-2 h-4 w-4" />
<template v-if="props.dateValue.start">
<template v-if="props.dateValue.end">
{{ df.format(props.dateValue.start.toDate(getLocalTimeZone())) }} -
{{ df.format(props.dateValue.end.toDate(getLocalTimeZone())) }}
</template>
<template v-else>
{{ df.format(props.dateValue.start.toDate(getLocalTimeZone())) }}
</template>
</template>
<template v-else> Pick a date </template>
</Button>
</PopoverTrigger>
<PopoverContent class="w-auto p-0">
<RangeCalendar v-model="props.dateValue" initial-focus :number-of-months="2"
@update:model-value="(date) => emit('update:dateValue', date)" />
</PopoverContent>
</Popover>
<PubMyUiDataTable
v-bind="config"
:rows="data"
:skeleton-size="props.paginationMeta?.pageSize"
/>
<PaginationView :pagination-meta="props.paginationMeta" @page-change="handlePageChange" />
</div>
</Dialog>
</template>
@@ -0,0 +1,94 @@
import type { Config } from '~/components/pub/my-ui/data-table'
import type { Patient } from '~/models/patient'
import { defineAsyncComponent } from 'vue'
import { educationCodes, genderCodes } from '~/lib/constants'
import { calculateAge } from '~/lib/utils'
const action = defineAsyncComponent(() => import('~/components/pub/my-ui/data/dropdown-action-dvvp.vue'))
export const config: Config = {
cols: [{width: 140}, {}, {}, {width: 140}, {width: 10},],
headers: [
[
{ label: 'Tanggal/Jam' },
{ label: 'Dokter' },
{ label: 'Tempat Layanan' },
{ label: 'Jenis' },
{ label: 'Jenis Pemeriksaan' },
{ label: 'Tanggal/Jam' },
],
],
keys: ['birth_date', 'person.name', 'person.name', 'person.name', 'person.name', 'birth_date',],
delKeyNames: [
{ key: 'code', label: 'Kode' },
{ key: 'name', label: 'Nama' },
],
parses: {
patientId: (rec: unknown): unknown => {
const patient = rec as Patient
return patient.number
},
identity_number: (rec: unknown): unknown => {
const { person } = rec as Patient
if (person.nationality == 'WNA') {
return person.passportNumber
}
return person.residentIdentityNumber || '-'
},
birth_date: (rec: unknown): unknown => {
const { person } = rec as Patient
if (typeof person.birthDate == 'object' && person.birthDate) {
return (person.birthDate as Date).toLocaleDateString('id-ID')
} else if (typeof person.birthDate == 'string') {
return (person.birthDate as string).substring(0, 10)
}
return person.birthDate
},
patient_age: (rec: unknown): unknown => {
const { person } = rec as Patient
return calculateAge(person.birthDate)
},
gender: (rec: unknown): unknown => {
const { person } = rec as Patient
if (typeof person.gender_code == 'number' && person.gender_code >= 0) {
return person.gender_code
} else if (typeof person.gender_code === 'string' && person.gender_code) {
return genderCodes[person.gender_code] || '-'
}
return '-'
},
education: (rec: unknown): unknown => {
const { person } = rec as Patient
if (typeof person.education_code == 'number' && person.education_code >= 0) {
return person.education_code
} else if (typeof person.education_code === 'string' && person.education_code) {
return educationCodes[person.education_code] || '-'
}
return '-'
},
},
components: {
action(rec, idx) {
return {
idx,
rec: rec as object,
component: action,
}
},
},
htmls: {
patient_address(_rec) {
return '-'
},
},
}
@@ -0,0 +1,66 @@
<script setup lang="ts">
import Dialog from '~/components/pub/my-ui/modal/dialog.vue'
import type { PaginationMeta } from '~/components/pub/my-ui/pagination/pagination.type'
import PaginationView from '~/components/pub/my-ui/pagination/pagination-view.vue'
import { config } from './consultation-list.cfg'
import { cn } from '~/lib/utils'
import { CalendarDate, DateFormatter, getLocalTimeZone } from '@internationalized/date'
import type { DateRange } from 'radix-vue'
import { CalendarIcon } from 'lucide-vue-next'
interface Props {
data: any[]
paginationMeta: PaginationMeta
dateValue: DateRange
}
const props = defineProps<Props>()
const isModalOpen = inject(`isConsultationHistoryOpen`) as Ref<boolean>
const df = new DateFormatter('en-US', { dateStyle: 'medium',})
const emit = defineEmits<{
pageChange: [page: number]
'update:dateValue': [value: DateRange]
}>()
function handlePageChange(page: number) {
emit('pageChange', page)
}
</script>
<template>
<Dialog v-model:open="isModalOpen" title="" size="2xl">
<div class="space-y-4">
<Popover>
<PopoverTrigger as-child>
<Button variant="outline" :class="cn('mb-1 w-[280px] justify-start text-left font-normal',
!props.dateValue && 'text-muted-foreground')">
<CalendarIcon class="mr-2 h-4 w-4" />
<template v-if="props.dateValue.start">
<template v-if="props.dateValue.end">
{{ df.format(props.dateValue.start.toDate(getLocalTimeZone())) }} -
{{ df.format(props.dateValue.end.toDate(getLocalTimeZone())) }}
</template>
<template v-else>
{{ df.format(props.dateValue.start.toDate(getLocalTimeZone())) }}
</template>
</template>
<template v-else> Pick a date </template>
</Button>
</PopoverTrigger>
<PopoverContent class="w-auto p-0">
<RangeCalendar v-model="props.dateValue" initial-focus :number-of-months="2"
@update:model-value="(date) => emit('update:dateValue', date)" />
</PopoverContent>
</Popover>
<PubMyUiDataTable
v-bind="config"
:rows="data"
:skeleton-size="props.paginationMeta?.pageSize"
/>
<PaginationView :pagination-meta="props.paginationMeta" @page-change="handlePageChange" />
</div>
</Dialog>
</template>
@@ -0,0 +1,51 @@
import type { Config } from '~/components/pub/my-ui/data-table'
import type { Patient } from '~/models/patient'
import { defineAsyncComponent } from 'vue'
const lampiranBtn = defineAsyncComponent(() => import('../_common/print-btn.vue'))
export const config: Config = {
cols: [{}, {}, {}, {}, {},],
headers: [
[
{ label: 'Tanggal/Jam' },
{ label: 'Dokter' },
{ label: 'Tempat Layanan' },
{ label: 'KSM' },
{ label: 'Tanggal/Jam' },
{ label: 'Tujuan' },
{ label: 'Dokter' },
{ label: 'Berkas' },
],
],
keys: ['birth_date', 'person.name', 'person.name', 'person.name', 'person.name', 'birth_date','person.name', 'action', ],
parses: {
birth_date: (rec: unknown): unknown => {
const { person } = rec as Patient
if (typeof person.birthDate == 'object' && person.birthDate) {
return (person.birthDate as Date).toLocaleDateString('id-ID')
} else if (typeof person.birthDate == 'string') {
return (person.birthDate as string).substring(0, 10)
}
return person.birthDate
},
},
components: {
action(rec, idx) {
return {
idx,
rec: rec as object,
component: lampiranBtn,
}
},
},
htmls: {
},
}
@@ -0,0 +1,66 @@
<script setup lang="ts">
import Dialog from '~/components/pub/my-ui/modal/dialog.vue'
import type { PaginationMeta } from '~/components/pub/my-ui/pagination/pagination.type'
import PaginationView from '~/components/pub/my-ui/pagination/pagination-view.vue'
import { config } from './farmacy-list.cfg'
import { cn } from '~/lib/utils'
import { CalendarDate, DateFormatter, getLocalTimeZone } from '@internationalized/date'
import type { DateRange } from 'radix-vue'
import { CalendarIcon } from 'lucide-vue-next'
interface Props {
data: any[]
paginationMeta: PaginationMeta
dateValue: DateRange
}
const props = defineProps<Props>()
const isModalOpen = inject(`isFarmacyHistoryOpen`) as Ref<boolean>
const df = new DateFormatter('en-US', { dateStyle: 'medium',})
const emit = defineEmits<{
pageChange: [page: number]
'update:dateValue': [value: DateRange]
}>()
function handlePageChange(page: number) {
emit('pageChange', page)
}
</script>
<template>
<Dialog v-model:open="isModalOpen" title="" size="2xl">
<div class="space-y-4">
<Popover>
<PopoverTrigger as-child>
<Button variant="outline" :class="cn('mb-1 w-[280px] justify-start text-left font-normal',
!props.dateValue && 'text-muted-foreground')">
<CalendarIcon class="mr-2 h-4 w-4" />
<template v-if="props.dateValue.start">
<template v-if="props.dateValue.end">
{{ df.format(props.dateValue.start.toDate(getLocalTimeZone())) }} -
{{ df.format(props.dateValue.end.toDate(getLocalTimeZone())) }}
</template>
<template v-else>
{{ df.format(props.dateValue.start.toDate(getLocalTimeZone())) }}
</template>
</template>
<template v-else> Pick a date </template>
</Button>
</PopoverTrigger>
<PopoverContent class="w-auto p-0">
<RangeCalendar v-model="props.dateValue" initial-focus :number-of-months="2"
@update:model-value="(date) => emit('update:dateValue', date)" />
</PopoverContent>
</Popover>
<PubMyUiDataTable
v-bind="config"
:rows="data"
:skeleton-size="props.paginationMeta?.pageSize"
/>
<PaginationView :pagination-meta="props.paginationMeta" @page-change="handlePageChange" />
</div>
</Dialog>
</template>
@@ -0,0 +1,39 @@
import type { Config } from '~/components/pub/my-ui/data-table'
import type { Patient } from '~/models/patient'
export const config: Config = {
cols: [{}, {}, {}, {}, {},],
headers: [
[
{ label: 'Tanggal Order' },
{ label: 'No Resep' },
{ label: 'Tempat Layanan' },
{ label: 'Nama Obat' },
{ label: 'Tanggal Disetujui' },
],
],
keys: ['birth_date', 'person.name', 'person.name', 'person.name', 'birth_date',],
parses: {
birth_date: (rec: unknown): unknown => {
const { person } = rec as Patient
if (typeof person.birthDate == 'object' && person.birthDate) {
return (person.birthDate as Date).toLocaleDateString('id-ID')
} else if (typeof person.birthDate == 'string') {
return (person.birthDate as string).substring(0, 10)
}
return person.birthDate
},
},
components: {
},
htmls: {
},
}
@@ -0,0 +1,65 @@
<script setup lang="ts">
import Dialog from '~/components/pub/my-ui/modal/dialog.vue'
import type { PaginationMeta } from '~/components/pub/my-ui/pagination/pagination.type'
import PaginationView from '~/components/pub/my-ui/pagination/pagination-view.vue'
import { config } from './national-program-list.cfg'
import { cn } from '~/lib/utils'
import { CalendarDate, DateFormatter, getLocalTimeZone } from '@internationalized/date'
import type { DateRange } from 'radix-vue'
import { CalendarIcon } from 'lucide-vue-next'
import type { Item } from '~/components/pub/my-ui/combobox'
import Select from '~/components/pub/my-ui/form/select.vue'
import * as DE from '~/components/pub/my-ui/doc-entry'
interface Props {
data: any[]
paginationMeta: PaginationMeta
searchValue: string
statusValue: string
}
const props = defineProps<Props>()
const isModalOpen = inject(`isNationalProgramServiceHistoryOpen`) as Ref<boolean>
const emit = defineEmits<{
pageChange: [page: number]
'update:searchValue': [value: string]
'update:statusValue': [value: string]
}>()
function handlePageChange(page: number) {
emit('pageChange', page)
}
const statusOptions: Item[] = [
{ value: 'all', label: 'All Statuses' },
{ value: 'pending', label: 'Pending' },
{ value: 'active', label: 'Active' },
{ value: 'completed', label: 'Completed' },
{ value: 'archived', label: 'Archived' },
]
</script>
<template>
<Dialog v-model:open="isModalOpen" title="" size="2xl">
<div class="space-y-4">
<DE.Block :col-count="4" class="" :cell-flex="false">
<Input
v-model="props.searchValue"
class=""
placeholder="Cari .."/>
<Select
:items="statusOptions"
:model-value="props.statusValue"
@update:model-value="(data) => emit('update:statusValue', data)"
/>
</DE.Block>
<PubMyUiDataTable
v-bind="config"
:rows="data"
:skeleton-size="props.paginationMeta?.pageSize"
/>
<PaginationView :pagination-meta="props.paginationMeta" @page-change="handlePageChange" />
</div>
</Dialog>
</template>
@@ -0,0 +1,30 @@
import type { Config } from '~/components/pub/my-ui/data-table'
import type { Patient } from '~/models/patient'
export const config: Config = {
cols: [{}, {}, {}, {}, {},],
headers: [
[
{ label: 'Nomor' },
{ label: 'Layanan Program Nasional' },
{ label: 'Status' },
],
],
keys: ['person.name', 'person.name', 'person.name',],
parses: {
// birth_date: (rec: unknown): unknown => {
// },
},
components: {
},
htmls: {
},
}
@@ -0,0 +1,66 @@
<script setup lang="ts">
import Dialog from '~/components/pub/my-ui/modal/dialog.vue'
import type { PaginationMeta } from '~/components/pub/my-ui/pagination/pagination.type'
import PaginationView from '~/components/pub/my-ui/pagination/pagination-view.vue'
import { config } from './supporting-list.cfg'
import { cn } from '~/lib/utils'
import { CalendarDate, DateFormatter, getLocalTimeZone } from '@internationalized/date'
import type { DateRange } from 'radix-vue'
import { CalendarIcon } from 'lucide-vue-next'
interface Props {
data: any[]
paginationMeta: PaginationMeta
dateValue: DateRange
}
const props = defineProps<Props>()
const isModalOpen = inject(`isSupportingHistoryOpen`) as Ref<boolean>
const df = new DateFormatter('en-US', { dateStyle: 'medium',})
const emit = defineEmits<{
pageChange: [page: number]
'update:dateValue': [value: DateRange]
}>()
function handlePageChange(page: number) {
emit('pageChange', page)
}
</script>
<template>
<Dialog v-model:open="isModalOpen" title="" size="2xl">
<div class="space-y-4">
<Popover>
<PopoverTrigger as-child>
<Button variant="outline" :class="cn('mb-1 w-[280px] justify-start text-left font-normal',
!props.dateValue && 'text-muted-foreground')">
<CalendarIcon class="mr-2 h-4 w-4" />
<template v-if="props.dateValue.start">
<template v-if="props.dateValue.end">
{{ df.format(props.dateValue.start.toDate(getLocalTimeZone())) }} -
{{ df.format(props.dateValue.end.toDate(getLocalTimeZone())) }}
</template>
<template v-else>
{{ df.format(props.dateValue.start.toDate(getLocalTimeZone())) }}
</template>
</template>
<template v-else> Pick a date </template>
</Button>
</PopoverTrigger>
<PopoverContent class="w-auto p-0">
<RangeCalendar v-model="props.dateValue" initial-focus :number-of-months="2"
@update:model-value="(date) => emit('update:dateValue', date)" />
</PopoverContent>
</Popover>
<PubMyUiDataTable
v-bind="config"
:rows="data"
:skeleton-size="props.paginationMeta?.pageSize"
/>
<PaginationView :pagination-meta="props.paginationMeta" @page-change="handlePageChange" />
</div>
</Dialog>
</template>
@@ -0,0 +1,39 @@
import type { Config } from '~/components/pub/my-ui/data-table'
import type { Patient } from '~/models/patient'
export const config: Config = {
cols: [{}, {}, {}, {}, {},],
headers: [
[
{ label: 'Tanggal Order' },
{ label: 'No Lab' },
{ label: 'Nama Pemeriksaan' },
{ label: 'Tanggal Pemeriksaan' },
],
],
keys: ['birth_date', 'person.name', 'person.name', 'birth_date',],
parses: {
birth_date: (rec: unknown): unknown => {
const { person } = rec as Patient
if (typeof person.birthDate == 'object' && person.birthDate) {
return (person.birthDate as Date).toLocaleDateString('id-ID')
} else if (typeof person.birthDate == 'string') {
return (person.birthDate as string).substring(0, 10)
}
return person.birthDate
},
},
components: {
},
htmls: {
// patient_address(_rec) {
// return '-'
// },
},
}
+14 -6
View File
@@ -4,22 +4,23 @@ import { defineAsyncComponent } from 'vue'
import { educationCodes, genderCodes } from '~/lib/constants'
import { calculateAge } from '~/lib/utils'
const action = defineAsyncComponent(() => import('~/components/pub/my-ui/data/dropdown-action-dud.vue'))
const action = defineAsyncComponent(() => import('~/components/pub/my-ui/data/dropdown-action-dvvp.vue'))
const statusBadge = defineAsyncComponent(() => import('./_common/verify-badge.vue'))
export const config: Config = {
cols: [{}, {}, {}, {}, {width: 3},],
cols: [{width: 140}, {}, {}, {width: 140}, {width: 10},],
headers: [
[
{ label: 'Tgl Rencana Kontrol' },
{ label: 'Spesialis/Sub Spesialis' },
{ label: 'Tgl Simpan' },
{ label: 'DPJP' },
{ label: 'Status SEP' },
{ label: 'KSM' },
{ label: 'Status' },
{ label: 'Action' },
],
],
keys: ['birth_date', 'number', 'person.name', 'birth_date', 'action'],
keys: ['birth_date', 'number', 'person.name', 'status', 'action'],
delKeyNames: [
{ key: 'code', label: 'Kode' },
@@ -83,6 +84,13 @@ export const config: Config = {
component: action,
}
},
status(rec, idx) {
return {
idx,
rec: rec as object,
component: statusBadge,
}
},
},
htmls: {
+19 -31
View File
@@ -2,42 +2,30 @@
import type { PaginationMeta } from '~/components/pub/my-ui/pagination/pagination.type'
import PaginationView from '~/components/pub/my-ui/pagination/pagination-view.vue'
import { config } from './list.cfg'
import DetailRow from '~/components/pub/my-ui/form/view/detail-row.vue';
interface Props {
data: any
data: any[]
paginationMeta: PaginationMeta
}
defineProps<Props>()
const emit = defineEmits<{
pageChange: [page: number]
}>()
function handlePageChange(page: number) {
emit('pageChange', page)
}
</script>
<template>
<article class="space-y-4">
<h1 class="font-medium text-[0.89rem]">Pemeriksaan Pasien</h1>
<div class="space-y-1">
<DetailRow label="Tanggal Masuk">{{ new Date().toLocaleDateString('id-ID') }}</DetailRow>
<DetailRow label="Tanggal Keluar">{{ new Date().toLocaleDateString('id-ID') }}</DetailRow>
<DetailRow label="Anamnesis">{{ `-` }}</DetailRow>
<DetailRow label="Pemeriksaan Fisik">{{ `-` }}</DetailRow>
<DetailRow label="Pemeriksaan Penunjang">{{ `-` }}</DetailRow>
</div>
<Separator class="" />
<h1 class="font-medium text-[0.89rem]">Diagnosis</h1>
<div class="space-y-1">
<DetailRow label="Diagnosis Utama">{{ `-` }}</DetailRow>
<DetailRow label="Diagnosis Sekunder">{{ `-` }}</DetailRow>
</div>
<Separator class="" />
<h1 class="font-medium text-[0.89rem]">Tindakan Operatif/Non Operatif</h1>
<div class="space-y-1">
<DetailRow label="Tindakan Operatif Utama">{{ `-` }}</DetailRow>
<DetailRow label="Tindakan /Prosedur">{{ `-` }}</DetailRow>
<DetailRow label="Medikamentosa">{{ `-` }}</DetailRow>
</div>
<Separator class="" />
<h1 class="font-medium text-[0.89rem]">Penatalaksanaan</h1>
<div class="space-y-1">
<DetailRow label="Lanjutan Penatalaksanaan">{{ `-` }}</DetailRow>
</div>
</article>
</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,97 @@
<script setup lang="ts">
import type { FormErrors } from '~/types/error'
import { toTypedSchema } from '@vee-validate/zod'
import FieldGroup from '~/components/pub/my-ui/form/field-group.vue'
import Field from '~/components/pub/my-ui/form/field.vue'
import Label from '~/components/pub/my-ui/form/label.vue'
import Select from '~/components/pub/my-ui/form/select.vue'
import { Form } from '~/components/pub/ui/form'
import InputBase from '~/components/pub/my-ui/form/input-base.vue'
import type { InstallationFormData } from '~/schemas/installation.schema'
const props = defineProps<{
schema: any
errors?: FormErrors
}>()
const emit = defineEmits<{
submit: [values: InstallationFormData, resetForm: () => void]
cancel: [resetForm: () => void]
}>()
const formSchema = toTypedSchema(props.schema)
// Form submission handler
function onSubmitForm(values: any, { resetForm }: { resetForm: () => void }) {
const formData: InstallationFormData = {
name: values.name || '',
code: values.code || '',
}
emit('submit', formData, resetForm)
}
// Form cancel handler
function onCancelForm({ resetForm }: { resetForm: () => void }) {
emit('cancel', resetForm)
}
const items = ref([
{ label: 'Rujukan Internal', value: 'ri' },
{ label: 'SEP Rujukan', value: 'sr' },
])
</script>
<template>
<Form
v-slot="{ handleSubmit, resetForm }"
as=""
keep-values
:validation-schema="formSchema"
>
<form id="entry-form" @submit="handleSubmit($event, (values) => onSubmitForm(values, { resetForm }))">
<div class="mb-5 border-b border-b-slate-300 pb-3 text-lg xl:text-xl">
<div class="flex flex-col justify-between">
<InputBase
field-name="name"
label="Nama"
placeholder="Masukkan Nama"
:errors="errors"/>
<InputBase
field-name="email"
label="Email"
placeholder="Masukkan Email"
:errors="errors"/>
<div class="mt-2">
<Label class="" for="password">Password</Label>
<Field class="" id="password" :errors="errors">
<FormField v-slot="{ componentField }" name="password">
<FormItem>
<FormControl>
<Input
id="password"
v-bind="componentField"
type="password"
class="w-full"
/>
</FormControl>
<FormMessage />
</FormItem>
</FormField>
</Field>
</div>
<InputBase
class="mb-2"
field-name="captha"
label="Captha"
placeholder="Masukkan Captha"
:errors="errors"/>
</div>
</div>
</form>
</Form>
</template>