215 lines
5.4 KiB
Vue
215 lines
5.4 KiB
Vue
<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 { ref, watch, inject } from 'vue'
|
|
|
|
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 })
|
|
|
|
// Define form fields
|
|
const [relatives, relativesAttrs] = defineField('relatives')
|
|
const [responsibleName, responsibleNameAttrs] = defineField('responsibleName')
|
|
const [responsiblePhone, responsiblePhoneAttrs] = defineField('responsiblePhone')
|
|
const [informant, informantAttrs] = defineField('informant')
|
|
const [witness1, witness1Attrs] = defineField('witness1')
|
|
const [witness2, witness2Attrs] = defineField('witness2')
|
|
const [tanggal, tanggalAttrs] = defineField('tanggal')
|
|
|
|
// Relatives list handling
|
|
const addRelative = () => {
|
|
relatives.value = [...(relatives.value || []), { name: '', phone: '' }]
|
|
}
|
|
|
|
const removeRelative = (index: number) => {
|
|
relatives.value = relatives.value.filter((_: any, i: number) => i !== index)
|
|
}
|
|
|
|
const validate = async () => {
|
|
const result = await _validate()
|
|
return {
|
|
valid: true,
|
|
data: result.values,
|
|
errors: result.errors,
|
|
}
|
|
}
|
|
|
|
defineExpose({ validate })
|
|
|
|
const icdPreview = inject('icdPreview')
|
|
|
|
const isExcluded = (key: string) => props.excludeFields?.includes(key)
|
|
</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>
|
|
<Input
|
|
v-model="tanggal"
|
|
v-bind="tanggalAttrs"
|
|
:disabled="props.isReadonly"
|
|
/>
|
|
</Field>
|
|
</Cell>
|
|
</Block>
|
|
|
|
<Separator class="mt-8" />
|
|
|
|
<div class="my-2 flex items-center justify-between">
|
|
<h1 class="font-semibold">Anggota Keluarga</h1>
|
|
<Button
|
|
type="button"
|
|
@click="addRelative"
|
|
>
|
|
+ Tambah
|
|
</Button>
|
|
</div>
|
|
|
|
<div
|
|
v-for="(item, idx) in relatives"
|
|
:key="idx"
|
|
class="my-2 rounded-md border border-slate-300 p-4"
|
|
>
|
|
<Block :colCount="2">
|
|
<Cell>
|
|
<Label dynamic>Nama Anggota Keluarga</Label>
|
|
<Field>
|
|
<Input v-model="relatives[idx].name" />
|
|
</Field>
|
|
</Cell>
|
|
|
|
<Cell>
|
|
<Label dynamic>No. Hp Anggota Keluarga</Label>
|
|
<Field>
|
|
<Input v-model="relatives[idx].phone" />
|
|
</Field>
|
|
</Cell>
|
|
</Block>
|
|
|
|
<button
|
|
type="button"
|
|
class="mt-3 text-sm text-red-500"
|
|
@click="removeRelative(idx)"
|
|
>
|
|
Hapus
|
|
</button>
|
|
</div>
|
|
|
|
<Separator class="mt-8" />
|
|
|
|
<!-- Responsible Section -->
|
|
<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>Nama Penanggung Jawab</Label>
|
|
<Field>
|
|
<Input
|
|
v-model="responsibleName"
|
|
v-bind="responsibleNameAttrs"
|
|
/>
|
|
</Field>
|
|
</Cell>
|
|
|
|
<Cell>
|
|
<Label dynamic>No. Hp Penanggung Jawab</Label>
|
|
<Field>
|
|
<Input
|
|
v-model="responsiblePhone"
|
|
v-bind="responsiblePhoneAttrs"
|
|
/>
|
|
</Field>
|
|
</Cell>
|
|
</Block>
|
|
</div>
|
|
|
|
<Separator class="mt-8" />
|
|
|
|
<!-- Informant -->
|
|
<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>Informant</Label>
|
|
<Field>
|
|
<Input
|
|
v-model="informant"
|
|
v-bind="informantAttrs"
|
|
/>
|
|
</Field>
|
|
</Cell>
|
|
</Block>
|
|
</div>
|
|
|
|
<Separator class="mt-8" />
|
|
|
|
<!-- Witnesses -->
|
|
<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>Saksi 1</Label>
|
|
<Field>
|
|
<Input
|
|
v-model="witness1"
|
|
v-bind="witness1Attrs"
|
|
/>
|
|
</Field>
|
|
</Cell>
|
|
|
|
<Cell>
|
|
<Label dynamic>Saksi 2</Label>
|
|
<Field>
|
|
<Input
|
|
v-model="witness2"
|
|
v-bind="witness2Attrs"
|
|
/>
|
|
</Field>
|
|
</Cell>
|
|
</Block>
|
|
</div>
|
|
</div>
|
|
</form>
|
|
</template>
|