feat(sep): add form entry
This commit is contained in:
@@ -2,14 +2,9 @@
|
||||
// types
|
||||
import type z from 'zod'
|
||||
import type { MaterialFormData } from '~/schemas/material'
|
||||
<<<<<<< HEAD:app/components/app/equipment/entry-form.vue
|
||||
=======
|
||||
// helpers
|
||||
import { toTypedSchema } from '@vee-validate/zod'
|
||||
import { useForm } from 'vee-validate'
|
||||
// components
|
||||
import Label from '~/components/pub/custom-ui/form/label.vue'
|
||||
>>>>>>> 266d5f740b15942ca7b8845c00573640fdc9a3b2:app/components/app/material/entry-form.vue
|
||||
|
||||
interface Props {
|
||||
schema: z.ZodSchema<any>
|
||||
|
||||
@@ -0,0 +1,123 @@
|
||||
<script setup lang="ts">
|
||||
// helpers
|
||||
import { toTypedSchema } from '@vee-validate/zod'
|
||||
import { useForm } from 'vee-validate'
|
||||
import * as z from 'zod'
|
||||
// components
|
||||
import { Button } from '~/components/pub/ui/button'
|
||||
import { Input } from '~/components/pub/ui/input'
|
||||
import { Label } from '~/components/pub/ui/label'
|
||||
import { Card, CardContent, CardHeader, CardTitle } from '~/components/pub/ui/card'
|
||||
import { Select } from '~/components/pub/ui/select'
|
||||
import { Textarea } from '~/components/pub/ui/textarea'
|
||||
import { RadioGroup, RadioGroupItem } from '~/components/pub/ui/radio-group'
|
||||
|
||||
const items = [
|
||||
{ value: 'item-1', label: 'Item 1' },
|
||||
{ value: 'item-2', label: 'Item 2' },
|
||||
{ value: 'item-3', label: 'Item 3' },
|
||||
]
|
||||
|
||||
// Validation schema
|
||||
const schema = z.object({
|
||||
tanggalSep: z.string().min(1, 'Tanggal SEP wajib diisi'),
|
||||
jalur: z.string().min(1, 'Pilih jalur'),
|
||||
noRm: z.string().min(1, 'No. RM wajib diisi'),
|
||||
namaPasien: z.string().min(1, 'Nama pasien wajib diisi'),
|
||||
noTelp: z.string().min(1, 'Nomor telepon wajib diisi'),
|
||||
klinikTujuan: z.string().min(1, 'Klinik tujuan wajib diisi'),
|
||||
diagnosaAwal: z.string().min(1, 'Diagnosa awal wajib diisi'),
|
||||
})
|
||||
|
||||
const { handleSubmit, errors, defineField } = useForm({
|
||||
validationSchema: toTypedSchema(schema),
|
||||
})
|
||||
|
||||
// Bind fields
|
||||
const [tanggalSep] = defineField('tanggalSep')
|
||||
const [jalur] = defineField('jalur')
|
||||
const [noRm] = defineField('noRm')
|
||||
const [namaPasien] = defineField('namaPasien')
|
||||
const [noTelp] = defineField('noTelp')
|
||||
const [klinikTujuan] = defineField('klinikTujuan')
|
||||
const [diagnosaAwal] = defineField('diagnosaAwal')
|
||||
|
||||
// Submit handler
|
||||
const onSubmit = handleSubmit((values) => {
|
||||
console.log('✅ Validated form values:', values)
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Card class="mx-auto w-full max-w-5xl">
|
||||
<CardHeader>
|
||||
<CardTitle></CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<form @submit.prevent="onSubmit" class="grid gap-6">
|
||||
<!-- Tanggal SEP & Jalur -->
|
||||
<div class="grid gap-4 md:grid-cols-2">
|
||||
<div>
|
||||
<Label for="tanggalSep">Tanggal SEP</Label>
|
||||
<Input id="tanggalSep" type="date" v-model="tanggalSep" />
|
||||
<p v-if="errors.tanggalSep" class="text-sm text-red-500">{{ errors.tanggalSep }}</p>
|
||||
</div>
|
||||
<div>
|
||||
<Label for="jalur">Jalur</Label>
|
||||
<Select v-model="jalur" :items="items" placeholder="Pilih jalur"></Select>
|
||||
<p v-if="errors.jalur" class="text-sm text-red-500">{{ errors.jalur }}</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Data Pasien -->
|
||||
<h3 class="text-lg font-semibold">Data Pasien</h3>
|
||||
<div class="grid gap-4 md:grid-cols-2">
|
||||
<div>
|
||||
<Label>No. RM*</Label>
|
||||
<Input v-model="noRm" />
|
||||
<p v-if="errors.noRm" class="text-sm text-red-500">{{ errors.noRm }}</p>
|
||||
</div>
|
||||
<div>
|
||||
<Label>Nama Pasien*</Label>
|
||||
<Input v-model="namaPasien" />
|
||||
<p v-if="errors.namaPasien" class="text-sm text-red-500">{{ errors.namaPasien }}</p>
|
||||
</div>
|
||||
<div>
|
||||
<Label>No. Telepon*</Label>
|
||||
<Input v-model="noTelp" />
|
||||
<p v-if="errors.noTelp" class="text-sm text-red-500">{{ errors.noTelp }}</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Data SEP -->
|
||||
<h3 class="text-lg font-semibold">Data SEP</h3>
|
||||
<div class="grid gap-4 md:grid-cols-2">
|
||||
<div>
|
||||
<Label>Klinik Tujuan*</Label>
|
||||
<Select v-model="klinikTujuan" :items="items" placeholder="Pilih klinik"></Select>
|
||||
<p v-if="errors.klinikTujuan" class="text-sm text-red-500">{{ errors.klinikTujuan }}</p>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<Label>Diagnosa Awal*</Label>
|
||||
<Input v-model="diagnosaAwal" />
|
||||
<p v-if="errors.diagnosaAwal" class="text-sm text-red-500">{{ errors.diagnosaAwal }}</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Catatan -->
|
||||
<div>
|
||||
<Label>Catatan</Label>
|
||||
<Textarea placeholder="Masukkan catatan opsional" />
|
||||
</div>
|
||||
|
||||
<!-- Actions -->
|
||||
<div class="mt-6 flex justify-end gap-4">
|
||||
<Button type="button" variant="outline">Riwayat SEP</Button>
|
||||
<Button type="button" variant="outline">Preview</Button>
|
||||
<Button type="submit">Simpan</Button>
|
||||
</div>
|
||||
</form>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</template>
|
||||
@@ -0,0 +1,20 @@
|
||||
<script setup lang="ts">
|
||||
|
||||
const isLoading = ref(false)
|
||||
|
||||
function onBack() {
|
||||
navigateTo('/bpjs/sep')
|
||||
}
|
||||
|
||||
async function onSubmit(data: any) {
|
||||
console.log(data)
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="mb-5 border-b border-b-slate-300 pb-3 text-lg xl:text-xl">
|
||||
<Icon name="i-lucide-panel-bottom" class="me-2" />
|
||||
<span class="font-semibold">Tambah</span> SEP
|
||||
</div>
|
||||
<AppSepEntryForm />
|
||||
</template>
|
||||
@@ -91,13 +91,15 @@ const headerPrep: HeaderPrep = {
|
||||
icon: 'i-lucide-panel-bottom',
|
||||
addNav: {
|
||||
label: 'Tambah',
|
||||
onClick: () => {},
|
||||
onClick: () => {
|
||||
navigateTo('/bpjs/sep/add')
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
async function getSepList() {
|
||||
isLoading.dataListLoading = true
|
||||
data.value = [...rows];
|
||||
data.value = [...rows]
|
||||
isLoading.dataListLoading = false
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
<script setup lang="ts">
|
||||
import type { PagePermission } from '~/models/role'
|
||||
import Error from '~/components/pub/base/error/error.vue'
|
||||
import { PAGE_PERMISSIONS } from '~/lib/page-permission'
|
||||
|
||||
definePageMeta({
|
||||
middleware: [],
|
||||
roles: ['doctor', 'nurse', 'admisi', 'pharmacy', 'billing', 'management'],
|
||||
title: 'Tambah SEP',
|
||||
contentFrame: 'cf-full-width',
|
||||
})
|
||||
|
||||
const route = useRoute()
|
||||
|
||||
useHead({
|
||||
title: () => route.meta.title as string,
|
||||
})
|
||||
|
||||
const roleAccess: PagePermission = PAGE_PERMISSIONS['/doctor']
|
||||
|
||||
const { checkRole, hasCreateAccess } = useRBAC()
|
||||
|
||||
// Check if user has access to this page
|
||||
const hasAccess = checkRole(roleAccess)
|
||||
if (!hasAccess) {
|
||||
throw createError({
|
||||
statusCode: 403,
|
||||
statusMessage: 'Access denied',
|
||||
})
|
||||
}
|
||||
|
||||
// Define permission-based computed properties
|
||||
const canCreate = true // hasCreateAccess(roleAccess)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div v-if="canCreate">
|
||||
<ContentSepEntry />
|
||||
</div>
|
||||
<Error v-else :status-code="403" />
|
||||
</template>
|
||||
Reference in New Issue
Block a user