feat (encounter): implement general consent feature

This commit is contained in:
Abizrh
2025-11-11 08:57:49 +07:00
parent db15ec9445
commit e62ee1b37e
9 changed files with 798 additions and 1 deletions
@@ -0,0 +1,241 @@
<script setup lang="ts">
import Block from '~/components/pub/my-ui/doc-entry/block.vue'
import Cell from '~/components/pub/my-ui/doc-entry/cell.vue'
import Field from '~/components/pub/my-ui/doc-entry/field.vue'
import Label from '~/components/pub/my-ui/doc-entry/label.vue'
// Helpers
import type z from 'zod'
import { toTypedSchema } from '@vee-validate/zod'
import { useForm } from 'vee-validate'
import { genBase } from '~/models/_base'
const props = defineProps<{
modelValue: any
schema: z.ZodSchema<any>
excludeFields?: string[]
isReadonly?: boolean
}>()
const emit = defineEmits<{
(e: 'update:modelValue', val: any): void
(e: 'submit', val: any): void
}>()
// Setup form
const {
validate: _validate,
defineField,
handleSubmit,
errors,
values,
} = useForm({
validationSchema: toTypedSchema(props.schema),
initialValues: props.modelValue,
})
watch(values, (val) => emit('update:modelValue', val), { deep: true })
const [primaryComplaint, primaryComplaintAttrs] = defineField('prim-compl')
const [pastDisease, pastDiseaseAttrs] = defineField('past-disease')
const [currentDisease, currentDiseaseAttrs] = defineField('current-disease')
const [gcs, gcsAttrs] = defineField('gcs')
const [respiratoryRate, respiratoryRateAttrs] = defineField('respiratory-rate')
const [respiratoryRateType, respiratoryRateTypeAttrs] = defineField('respiratory-rate-type')
const [pulse, pulseAttrs] = defineField('pulse')
const [pulseType, pulseTypeAttrs] = defineField('pulse-type')
const [rightArmBp, rightArmBpAttrs] = defineField('right-arm-bp')
const [leftArmBp, leftArmBpAttrs] = defineField('left-arm-bp')
const [axillaryTemp, axillaryTempAttrs] = defineField('axillary-temp')
const [rektalTemp, rektalTempAttrs] = defineField('rektal-temp')
const [skin, skinAttrs] = defineField('skin')
const [head, headAttrs] = defineField('head')
const [ear, earAttrs] = defineField('ear')
const [nose, noseAttrs] = defineField('nose')
const [oralCavity, oralCavityAttrs] = defineField('oral-cavity')
const [eye, eyeAttrs] = defineField('eye')
const [otherBodyPart, otherBodyPartAttrs] = defineField('other-body-part')
const [neck, neckAttrs] = defineField('neck')
const [thyroid, thyroidAttrs] = defineField('thyroid')
const [thorax, thoraxAttrs] = defineField('thorax')
const [heart, heartAttrs] = defineField('heart')
const [lung, lungAttrs] = defineField('lung')
const [abdomen, abdomenAttrs] = defineField('abdomen')
const [heart2, heart2Attrs] = defineField('heart2')
const [lien, lienAttrs] = defineField('lien')
const [back, backAttrs] = defineField('back')
const [extremity, extremityAttrs] = defineField('extremity')
const [gender, genderAttrs] = defineField('gender')
const [rectum, rectumAttrs] = defineField('rectum')
const [systemSyaraf, systemSyarafAttrs] = defineField('system-syaraf')
const [nervousSystem, nervousSystemAttrs] = defineField('nervous-system')
const [cardioRespiratory, cardioRespiratoryAttrs] = defineField('cardio-respiratory')
const [imaging, imagingAttrs] = defineField('imaging')
const [laboratory, laboratoryAttrs] = defineField('laboratory')
const validate = async () => {
const result = await _validate()
console.log('Component validate() result:', result)
return {
valid: true,
data: result.values,
errors: result.errors,
}
}
defineExpose({ validate })
const icdPreview = inject('icdPreview')
const isExcluded = (key: string) => props.excludeFields?.includes(key)
const disorders = ref<string[]>([])
const therapies = ref<string[]>([])
const summary = ref('')
const disorderOptions = [
'Fungsi Otot',
'Fungsi Sendi',
'Fungsi Jalan',
'Fungsi Syaraf',
'Fungsi Koordinasi',
'Jantung',
'Fungsi Respirasi',
'Fungsi Menelan',
'Fungsi Bladder',
'Fungsi Bowel',
'Fungsi Luhur',
'Fungsi Kontrol Postur',
'Fungsi Eksekusi',
'Fungsi Ortosa/Protesa',
'Gangguan Aktivitas Sehari-hari',
'Lainnya',
]
const therapyOptions = ['Terapi Latihan', 'Modalitas Fisik', 'Protesa/Ortosa', 'Medikamentosa', 'Lain-lain: Konsultasi']
</script>
<template>
<form id="entry-form">
<div class="mb-5 border-b border-b-slate-300 pb-3 text-lg xl:text-xl">
<Block>
<Cell>
<Label dynamic>Tanggal</Label>
<Field :errMessage="errors['prim-compl']">
<Textarea
v-model="primaryComplaint"
v-bind="primaryComplaintAttrs"
/>
</Field>
</Cell>
</Block>
<Separator class="mt-8" />
<div class="my-2">
<h1 class="font-semibold">Anggota Keluarga dan Penanggung Jawab</h1>
</div>
<div class="my-2 rounded-md border border-slate-300 p-4">
<Block :colCount="2">
<Cell>
<Label dynamic>Pernapasan</Label>
<Field>
<Input
v-model="respiratoryRate"
v-bind="respiratoryRateAttrs"
/>
</Field>
</Cell>
<Cell>
<Label dynamic>Jenis</Label>
<Field>
<Input
v-model="respiratoryRateType"
v-bind="respiratoryRateTypeAttrs"
/>
</Field>
</Cell>
</Block>
</div>
<div class="my-2">
<h1 class="font-semibold">Penanggung Jawab</h1>
</div>
<div class="my-2 rounded-md border border-slate-300 p-4">
<Block :colCount="2">
<Cell>
<Label dynamic>Pernapasan</Label>
<Field>
<Input
v-model="respiratoryRate"
v-bind="respiratoryRateAttrs"
/>
</Field>
</Cell>
<Cell>
<Label dynamic>Jenis</Label>
<Field>
<Input
v-model="respiratoryRateType"
v-bind="respiratoryRateTypeAttrs"
/>
</Field>
</Cell>
</Block>
</div>
<Separator class="mt-8" />
<div class="my-2">
<h1 class="font-semibold">Pemberi Informasi</h1>
</div>
<div class="my-2 rounded-md border border-slate-300 p-4">
<Block>
<Cell>
<Label dynamic>Jenis</Label>
<Field>
<Input
v-model="respiratoryRateType"
v-bind="respiratoryRateTypeAttrs"
/>
</Field>
</Cell>
</Block>
</div>
<Separator class="mt-8" />
<div class="my-2">
<h1 class="font-semibold">Saksi</h1>
</div>
<div class="my-2 rounded-md border border-slate-300 p-4">
<Block :colCount="2">
<Cell>
<Label dynamic>Pernapasan</Label>
<Field>
<Input
v-model="respiratoryRate"
v-bind="respiratoryRateAttrs"
/>
</Field>
</Cell>
<Cell>
<Label dynamic>Jenis</Label>
<Field>
<Input
v-model="respiratoryRateType"
v-bind="respiratoryRateTypeAttrs"
/>
</Field>
</Cell>
</Block>
</div>
</div>
</form>
</template>
@@ -0,0 +1,57 @@
import type { Config, RecComponent, RecStrFuncComponent, RecStrFuncUnknown } from '~/components/pub/my-ui/data-table'
import { defineAsyncComponent } from 'vue'
import type { GeneralConsent } from '~/models/general-consent'
type SmallDetailDto = any
const action = defineAsyncComponent(() => import('~/components/pub/my-ui/data/dropdown-action-ud.vue'))
export const config: Config = {
cols: [{ width: 100 }, {}, {}, {}, { width: 50 }],
headers: [
[
{ label: 'Tanggal' },
{ label: 'Anggota Keluarga' },
{ label: 'Penanggung Jawab' },
{ label: 'Pemberi Informasi' },
{ label: 'Saksi 1' },
{ label: 'Saksi 2' },
{ label: '' },
],
],
keys: ['date', 'dstUnit.name', 'dstDoctor.name', 'responsible', 'problem', 'solution', 'action'],
delKeyNames: [
{ key: 'data', label: 'Tanggal' },
{ key: 'dstDoctor.name', label: 'Dokter' },
],
parses: {
action(rec, idx) {
const res: RecComponent = {
idx,
rec: rec as object,
component: action,
props: {
size: 'sm',
},
}
return res
},
date(rec) {
const recX = rec as GeneralConsent
return recX.date?.substring(0, 10) || '-'
},
},
components: {
action(rec, idx) {
const res: RecComponent = {
idx,
rec: rec as object,
component: action,
props: {
size: 'sm',
},
}
return res
},
} as RecStrFuncComponent,
htmls: {} as RecStrFuncUnknown,
}
@@ -0,0 +1,34 @@
<script setup lang="ts">
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'
interface Props {
data: any[]
paginationMeta: PaginationMeta
}
const props = 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"
/>
<!-- FIXME: pindahkan ke content/division/list.vue -->
<PaginationView
:pagination-meta="paginationMeta"
@page-change="handlePageChange"
/>
</div>
</template>