impl: blood calc, prosedur picker

wip:
radio bloods(note. masih crash dan modelValue ga bisa liftup)

Picker Prosedur
- cherry-pick
- done:  integrasi prosedur w/ therapy-protocol-
This commit is contained in:
Khafid Prayoga
2025-11-26 14:00:15 +07:00
parent 5ad286a44e
commit 71c2833bf2
7 changed files with 167 additions and 30 deletions
+6 -3
View File
@@ -7,13 +7,16 @@ import type { PaginationMeta } from '~/components/pub/my-ui/pagination/paginatio
// Configs
import { config } from './list-cfg'
import type { Config } from '~/components/pub/my-ui/data-table'
interface Props {
data: any[]
paginationMeta: PaginationMeta
tableConfig?: Config
}
defineProps<Props>()
const props = withDefaults(defineProps<Props>(), {
tableConfig: () => config,
})
const emit = defineEmits<{
pageChange: [page: number]
@@ -27,7 +30,7 @@ function handlePageChange(page: number) {
<template>
<div class="space-y-4">
<PubMyUiDataTable
v-bind="config"
v-bind="props.tableConfig"
:rows="data"
:skeleton-size="paginationMeta?.pageSize"
/>
@@ -14,6 +14,7 @@ import { is } from 'date-fns/locale'
interface Props {
fieldName: string
title: string
subTitle?: string
}
const props = defineProps<Props>()
@@ -24,18 +25,29 @@ provide(`isProcedurePickerDialogOpen`, isProcedurePickerDialogOpen)
<template>
<div class="">
<div class="mb-2 flex items-center justify-between">
<h1 class="mb-2 font-medium">{{ title }}</h1>
<Button @click="isProcedurePickerDialogOpen = true" size="xs" variant="outline"
class="text-orange-400 border-orange-400 bg-transparent">
<Icon name="i-lucide-search" class="h-4 w-4 align-middle transition-colors" />
Pilih Diagnosis
<p class="mb-2 font-medium">{{ title }}</p>
<Button
type="button"
@click="isProcedurePickerDialogOpen = true"
size="xs"
variant="outline"
class="border-orange-400 bg-transparent text-orange-400"
>
<Icon
name="i-lucide-search"
class="h-4 w-4 align-middle transition-colors"
/>
{{ subTitle || 'Pilih Diagnosis' }}
</Button>
</div>
<FieldArray v-slot="{ fields, push, remove }" :name="props.fieldName">
<FieldArray
v-slot="{ fields, push, remove }"
:name="props.fieldName"
>
<ProcedureListDialog :process-fn="push" />
<div class="border border-gray-200 rounded-lg overflow-hidden">
<div class="overflow-hidden rounded-lg border border-gray-200">
<Table>
<TableHeader class="bg-gray-100">
<TableRow>
@@ -45,12 +57,23 @@ provide(`isProcedurePickerDialogOpen`, isProcedurePickerDialogOpen)
</TableRow>
</TableHeader>
<TableBody>
<TableRow v-for="(field, idx) in fields" :key="idx">
<TableRow
v-for="(field, idx) in fields"
:key="idx"
>
<TableCell class="">{{ field.value?.name }}</TableCell>
<TableCell class="">{{ field.value?.code }}</TableCell>
<TableCell class="">
<Button type="button" variant="destructive" size="sm" @click="remove(idx)">
<Icon name="i-lucide-trash-2" class="h-4 w-4" />
<Button
type="button"
variant="destructive"
size="sm"
@click="remove(idx)"
>
<Icon
name="i-lucide-trash-2"
class="h-4 w-4"
/>
</Button>
</TableCell>
</TableRow>
@@ -16,6 +16,7 @@ import Separator from '~/components/pub/ui/separator/Separator.vue'
// form field components
import {
FillNotes,
RadioBloods,
SelectBilling,
SelectBirthPlace,
SelectBirthType,
@@ -174,18 +175,12 @@ const onSubmit = handleSubmit(
v-slot="{ section }"
title="Tindakan Operatif/Non Operatif Lain"
>
<p class="text-lg font-semibold">{{ section }}</p>
<!-- <p class="text-lg font-semibold">{{ section }}</p> -->
<DE.Block
:col-count="4"
:col-count="2"
:cell-flex="false"
>
<InputBase
field-name="operationType"
label="Tindakan Opearatif/Non"
placeholder="Masukkan tindakan operatif/non"
:col-span="2"
/>
<slot name="procedures" />
</DE.Block>
</Fragment>
@@ -343,7 +338,11 @@ const onSubmit = handleSubmit(
:col-count="3"
:cell-flex="false"
>
bloods
<RadioBloods
field-name="isNewBorn"
label="Jenis & Jumlah Darah Masuk"
is-required
/>
</DE.Block>
<DE.Block
@@ -1,4 +1,5 @@
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'
@@ -0,0 +1,103 @@
<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"
>
<FormItem>
<FormControl>
<RadioGroup
v-bind="radioField"
: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('flex items-center gap-3', radioItemClass)"
>
<div class="flex min-w-fit items-center gap-2">
<RadioGroupItem
:id="`${fieldName}-${index}`"
:value="option.value"
class="h-5 w-5 border-muted-foreground data-[state=checked]:border-primary data-[state=checked]:text-primary"
/>
<RadioLabel
:for="`${fieldName}-${index}`"
:class="cn('min-w-[30px] cursor-pointer text-sm font-medium leading-none', labelClass)"
>
{{ option.label }}
</RadioLabel>
</div>
<FormField
v-slot="{ componentField }"
:name="`amount_${option.value}`"
>
<FormItem>
<FormControl>
<div class="relative w-[140px]">
<Input
v-bind="componentField"
placeholder="00"
class="pr-10"
:disabled="radioField.modelValue !== option.value || isDisabled"
@input="(e: Event) => {
const target = e.target as HTMLInputElement
const value = target.value.replace(/\D/g, '')
if (target.value !== value) {
target.value = value
componentField['onInput'](e)
}
}"
/>
<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>
<FormMessage class="ml-0 mt-1" />
</FormItem>
</FormField>
</DE.Field>
</DE.Cell>
</template>
@@ -6,6 +6,7 @@ import type { TreatmentReportFormData } from '~/schemas/treatment-report.schema'
// components
import { toast } from '~/components/pub/ui/toast'
import AppTreatmentReportEntry from '~/components/app/treatment-report/entry-form.vue'
import ArrangementProcedurePicker from '~/components/app/therapy-protocol/picker-dialog/arrangement-procedure/procedure-picker.vue'
const doctors = ref<Doctor[]>([])
@@ -34,7 +35,16 @@ const doctors = ref<Doctor[]>([])
operatorTeam: {
// dpjpId: -1,
},
// procedures: [{ id: 5, code: 'ROC0100', name: 'Accute Appendictis' }],
} as TreatmentReportFormData
"
/>
>
<template #procedures>
<ArrangementProcedurePicker
field-name="procedures"
title="Tindakan Operatif/Non-Operatif Lain"
sub-title="Pilih Prosedur"
/>
</template>
</AppTreatmentReportEntry>
</template>
+4 -6
View File
@@ -24,6 +24,8 @@ const props = defineProps<{
iconName?: string
}>()
const { class: containerClass } = props
function handleInput(event: Event) {
const target = event.target as HTMLInputElement
let value = target.value
@@ -69,18 +71,14 @@ const hasError = computed(() => !!fieldError.value)
:name="fieldName"
>
<FormItem>
<FormControl class="relative">
<FormControl :class="cn('relative', containerClass)">
<div class="relative w-full max-w-sm items-center">
<Input
:disabled="isDisabled"
v-bind="componentField"
:placeholder="placeholder"
:maxlength="maxLength"
:class="
cn(
hasError && 'border-red-500 focus-visible:border-red-500 focus-visible:ring-red-500',
)
"
:class="cn(hasError && 'border-red-500 focus-visible:border-red-500 focus-visible:ring-red-500')"
autocomplete="off"
aria-autocomplete="none"
autocorrect="off"