Fix Dialog Consultation (#124)
This commit is contained in:
@@ -0,0 +1,126 @@
|
||||
<script setup lang="ts">
|
||||
// Components
|
||||
import * as DE from '~/components/pub/my-ui/doc-entry'
|
||||
|
||||
// Types
|
||||
import type { ConsultationFormData } from '~/schemas/consultation.schema.ts'
|
||||
|
||||
// Helpers
|
||||
import type z from 'zod'
|
||||
import { toTypedSchema } from '@vee-validate/zod'
|
||||
import { useForm } from 'vee-validate'
|
||||
import Textarea from '~/components/pub/ui/textarea/Textarea.vue'
|
||||
import type { CreateDto } from '~/models/consultation'
|
||||
|
||||
interface Props {
|
||||
schema: z.ZodSchema<any>
|
||||
values: CreateDto
|
||||
encounter_id: number
|
||||
units: { value: string; label: string }[]
|
||||
isLoading?: boolean
|
||||
isReadonly?: boolean
|
||||
}
|
||||
|
||||
const props = defineProps<Props>()
|
||||
const isLoading = props.isLoading !== undefined ? props.isLoading : false
|
||||
const isReadonly = props.isReadonly !== undefined ? props.isReadonly : false
|
||||
const emit = defineEmits<{
|
||||
submit: [values: ConsultationFormData, resetForm: () => void]
|
||||
cancel: [resetForm: () => void]
|
||||
}>()
|
||||
|
||||
const today = new Date()
|
||||
const { defineField, errors, meta } = useForm({
|
||||
validationSchema: toTypedSchema(props.schema),
|
||||
initialValues: {
|
||||
date: props.values.date || today.toISOString().slice(0, 10),
|
||||
problem: '',
|
||||
dstUnit_id: 0,
|
||||
} as Partial<ConsultationFormData>,
|
||||
})
|
||||
|
||||
const [date, dateAttrs] = defineField('date')
|
||||
const [unit_id, unitAttrs] = defineField('unit_id')
|
||||
const [problem, problemAttrs] = defineField('problem')
|
||||
|
||||
// Fill fields from props.values if provided
|
||||
if (props.values) {
|
||||
if (props.values.date !== undefined) date.value = props.values.date.substring(0, 10)
|
||||
if (props.values.dstUnit_id !== undefined) unit_id.value = props.values.dstUnit_id
|
||||
if (props.values.problem !== undefined) problem.value = props.values.problem
|
||||
}
|
||||
|
||||
const resetForm = () => {
|
||||
date.value = date.value ?? today.toISOString().slice(0, 10)
|
||||
unit_id.value = 0
|
||||
problem.value = ''
|
||||
}
|
||||
|
||||
// Form submission handler
|
||||
function onSubmitForm(values: any) {
|
||||
const formData: ConsultationFormData = {
|
||||
encounter_id: props.encounter_id,
|
||||
date: date.value ? `${date.value}T00:00:00Z` : '',
|
||||
problem: problem.value || '',
|
||||
dstUnit_id: unit_id.value || 0,
|
||||
}
|
||||
emit('submit', formData, resetForm)
|
||||
}
|
||||
|
||||
// Form cancel handler
|
||||
function onCancelForm() {
|
||||
emit('cancel', resetForm)
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<form id="form-division" @submit.prevent>
|
||||
<DE.Block labelSize="thin" class="!mb-2.5 !pt-0 xl:!mb-3" :colCount="3" :cellFlex="false">
|
||||
<DE.Cell>
|
||||
<DE.Label>Tanggal</DE.Label>
|
||||
<DE.Field :errMessage="errors.code">
|
||||
<Input
|
||||
v-model.number="date"
|
||||
icon-name="i-lucide-chevron-down"
|
||||
v-bind="dateAttrs"
|
||||
readonly
|
||||
/>
|
||||
</DE.Field>
|
||||
</DE.Cell>
|
||||
<DE.Cell>
|
||||
<DE.Label>Unit</DE.Label>
|
||||
<DE.Field :errMessage="errors.unit_id">
|
||||
{{ errors.unit_id }}
|
||||
<Select
|
||||
id="strUnit_id"
|
||||
v-model.number="unit_id"
|
||||
icon-name="i-lucide-chevron-down"
|
||||
placeholder="Pilih kelompok obat"
|
||||
v-bind="unitAttrs"
|
||||
:items="props.units || []"
|
||||
:disabled="isLoading || isReadonly"
|
||||
/>
|
||||
<!-- <Input type="number" id="unit_id" v-model.number="unit_id" v-bind="unitAttrs" :disabled="isLoading || isReadonly" /> -->
|
||||
</DE.Field>
|
||||
</DE.Cell>
|
||||
<DE.Cell :colSpan="3">
|
||||
<DE.Label>Uraian</DE.Label>
|
||||
<DE.Field :errMessage="errors.problem">
|
||||
<Textarea id="problem" v-model="problem" v-bind="problemAttrs" :disabled="isLoading || isReadonly" />
|
||||
</DE.Field>
|
||||
</DE.Cell>
|
||||
</DE.Block>
|
||||
<div class="my-2 flex justify-end gap-2 py-2">
|
||||
<Button type="button" variant="secondary" class="w-[120px]" @click="onCancelForm"> Kembali </Button>
|
||||
<Button
|
||||
v-if="!isReadonly"
|
||||
type="button"
|
||||
class="w-[120px]"
|
||||
:disabled="isLoading || !meta.valid"
|
||||
@click="onSubmitForm"
|
||||
>
|
||||
Simpan
|
||||
</Button>
|
||||
</div>
|
||||
</form>
|
||||
</template>
|
||||
@@ -0,0 +1,54 @@
|
||||
import type { Config, RecComponent, RecStrFuncComponent, RecStrFuncUnknown } from '~/components/pub/my-ui/data-table'
|
||||
import { defineAsyncComponent } from 'vue'
|
||||
import type { Consultation } from '~/models/consultation'
|
||||
|
||||
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: 'Tujuan' },
|
||||
{ label: 'Dokter' },
|
||||
{ label: 'Pertanyaan' },
|
||||
{ label: 'Jawaban' },
|
||||
{ label: '' },
|
||||
]],
|
||||
keys: ['date', 'dstUnit.name', 'dstDoctor.name', '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 Consultation
|
||||
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,31 @@
|
||||
<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>
|
||||
@@ -0,0 +1,145 @@
|
||||
<script setup lang="ts">
|
||||
import type { TreeItem } from '~/components/pub/my-ui/select-tree/type'
|
||||
import type { FormErrors } from '~/types/error'
|
||||
import { toTypedSchema } from '@vee-validate/zod'
|
||||
import TreeSelect from '~/components/pub/my-ui/select-tree/tree-select.vue'
|
||||
import Combobox from '~/components/pub/my-ui/form/combobox.vue'
|
||||
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 { Form } from '~/components/pub/ui/form'
|
||||
|
||||
interface DivisionFormData {
|
||||
name: string
|
||||
code: string
|
||||
parentId: string
|
||||
}
|
||||
const props = defineProps<{
|
||||
division: {
|
||||
msg: {
|
||||
placeholder: string
|
||||
search: string
|
||||
empty: string
|
||||
}
|
||||
items: {
|
||||
value: string
|
||||
label: string
|
||||
}[]
|
||||
}
|
||||
divisionTree?: {
|
||||
msg: {
|
||||
placeholder: string
|
||||
search: string
|
||||
empty: string
|
||||
}
|
||||
data: TreeItem[]
|
||||
onFetchChildren: (parentId: string) => Promise<void>
|
||||
}
|
||||
schema: any
|
||||
initialValues?: Partial<DivisionFormData>
|
||||
errors?: FormErrors
|
||||
}>()
|
||||
|
||||
const emit = defineEmits<{
|
||||
'submit': [values: DivisionFormData, resetForm: () => void]
|
||||
'cancel': [resetForm: () => void]
|
||||
}>()
|
||||
|
||||
const formSchema = toTypedSchema(props.schema)
|
||||
|
||||
// Form submission handler
|
||||
function onSubmitForm(values: any, { resetForm }: { resetForm: () => void }) {
|
||||
const formData: DivisionFormData = {
|
||||
name: values.name || '',
|
||||
code: values.code || '',
|
||||
parentId: values.parentId || '',
|
||||
}
|
||||
emit('submit', formData, resetForm)
|
||||
}
|
||||
|
||||
// Form cancel handler
|
||||
function onCancelForm({ resetForm }: { resetForm: () => void }) {
|
||||
emit('cancel', resetForm)
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Form
|
||||
v-slot="{ handleSubmit, resetForm }" as="" keep-values :validation-schema="formSchema"
|
||||
:initial-values="initialValues"
|
||||
>
|
||||
<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">
|
||||
<FieldGroup>
|
||||
<Label label-for="name">Nama</Label>
|
||||
<Field id="name" :errors="errors">
|
||||
<FormField v-slot="{ componentField }" name="name">
|
||||
<FormItem>
|
||||
<FormControl>
|
||||
<Input
|
||||
id="name" type="text" placeholder="Masukkan nama divisi" autocomplete="off"
|
||||
v-bind="componentField"
|
||||
/>
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
</FormField>
|
||||
</Field>
|
||||
</FieldGroup>
|
||||
|
||||
<FieldGroup>
|
||||
<Label label-for="code">Kode</Label>
|
||||
<Field id="code" :errors="errors">
|
||||
<FormField v-slot="{ componentField }" name="code">
|
||||
<FormItem>
|
||||
<FormControl>
|
||||
<Input id="code" type="text" placeholder="Masukkan kode divisi" autocomplete="off" v-bind="componentField" />
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
</FormField>
|
||||
</Field>
|
||||
</FieldGroup>
|
||||
|
||||
<FieldGroup>
|
||||
<Label label-for="parentId">Divisi Induk</Label>
|
||||
<Field id="parentId" :errors="errors">
|
||||
<FormField v-slot="{ componentField }" name="parentId">
|
||||
<FormItem>
|
||||
<FormControl>
|
||||
<!-- Gunakan TreeSelect jika divisionTree tersedia, fallback ke Combobox -->
|
||||
<TreeSelect
|
||||
v-if="props.divisionTree"
|
||||
id="parentId"
|
||||
:model-value="componentField.modelValue"
|
||||
:data="props.divisionTree.data"
|
||||
:on-fetch-children="props.divisionTree.onFetchChildren"
|
||||
@update:model-value="componentField.onChange"
|
||||
/>
|
||||
<Combobox
|
||||
v-else
|
||||
id="parentId" v-bind="componentField" :items="props.division.items"
|
||||
:placeholder="props.division.msg.placeholder" :search-placeholder="props.division.msg.search"
|
||||
:empty-message="props.division.msg.empty"
|
||||
/>
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
</FormField>
|
||||
</Field>
|
||||
</FieldGroup>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="flex justify-end gap-2 mt-4">
|
||||
<Button type="button" variant="outline" @click="onCancelForm({ resetForm })">
|
||||
Batal
|
||||
</Button>
|
||||
<Button type="submit">
|
||||
Simpan
|
||||
</Button>
|
||||
</div>
|
||||
</form>
|
||||
</Form>
|
||||
</template>
|
||||
@@ -0,0 +1,165 @@
|
||||
<script setup lang="ts">
|
||||
import TreeSelect from '~/components/pub/my-ui/select-tree/tree-select.vue'
|
||||
|
||||
/**
|
||||
* DEMO COMPONENT - Tree Select dengan Lazy Loading
|
||||
*
|
||||
* Komponen ini adalah contoh penggunaan TreeSelect dengan data teknologi.
|
||||
* Untuk penggunaan dalam aplikasi nyata, lihat komponen content/division/entry.vue
|
||||
* yang menggunakan tree select untuk data divisi rumah sakit.
|
||||
*/
|
||||
|
||||
// Tipe data untuk konsistensi
|
||||
interface TreeItem {
|
||||
value: string
|
||||
label: string
|
||||
hasChildren: boolean
|
||||
children?: TreeItem[]
|
||||
}
|
||||
|
||||
// State untuk data pohon demo - data teknologi sebagai contoh
|
||||
const treeData = ref<TreeItem[]>([
|
||||
{ value: 'frontend', label: 'Frontend Development', hasChildren: true },
|
||||
{ value: 'backend', label: 'Backend Development', hasChildren: true },
|
||||
{ value: 'mobile', label: 'Mobile Development', hasChildren: true },
|
||||
{ value: 'devops', label: 'DevOps & Infrastructure', hasChildren: false },
|
||||
])
|
||||
|
||||
// State untuk menampung nilai yang dipilih
|
||||
const selectedValue = ref<string>()
|
||||
|
||||
// --- DEMO LOGIC: SIMULASI API DAN MANIPULASI DATA ---
|
||||
|
||||
// Helper: Fungsi rekursif untuk mencari dan menyisipkan data anak ke dalam state
|
||||
function findAndInsertChildren(nodes: TreeItem[], parentId: string, newChildren: TreeItem[]): boolean {
|
||||
for (let i = 0; i < nodes.length; i++) {
|
||||
const node = nodes[i]
|
||||
if (node && node.value === parentId) {
|
||||
// Gunakan Vue.set equivalent untuk memastikan reactivity
|
||||
node.children = [...newChildren]
|
||||
console.log(`[findAndInsertChildren] Updated children for ${parentId}:`, node.children)
|
||||
return true
|
||||
}
|
||||
if (node && node.children && findAndInsertChildren(node.children, parentId, newChildren)) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// Fungsi demo untuk simulasi fetch data dari API
|
||||
async function handleFetchChildren(parentId: string): Promise<void> {
|
||||
console.log(`[DEMO] Mengambil data anak untuk parent: ${parentId}`)
|
||||
|
||||
// Simulasi delay API call
|
||||
await new Promise(resolve => setTimeout(resolve, 600))
|
||||
|
||||
let childrenData: TreeItem[] = []
|
||||
|
||||
// Sample data berdasarkan parent ID
|
||||
switch (parentId) {
|
||||
case 'frontend':
|
||||
childrenData = [
|
||||
{ value: 'vue', label: 'Vue.js', hasChildren: true },
|
||||
{ value: 'react', label: 'React.js', hasChildren: true },
|
||||
{ value: 'angular', label: 'Angular', hasChildren: false },
|
||||
{ value: 'svelte', label: 'Svelte', hasChildren: false },
|
||||
]
|
||||
break
|
||||
case 'backend':
|
||||
childrenData = [
|
||||
{ value: 'nodejs', label: 'Node.js', hasChildren: true },
|
||||
{ value: 'python', label: 'Python', hasChildren: true },
|
||||
{ value: 'golang', label: 'Go', hasChildren: false },
|
||||
{ value: 'rust', label: 'Rust', hasChildren: false },
|
||||
]
|
||||
break
|
||||
case 'mobile':
|
||||
childrenData = [
|
||||
{ value: 'flutter', label: 'Flutter', hasChildren: false },
|
||||
{ value: 'react-native', label: 'React Native', hasChildren: false },
|
||||
{ value: 'ionic', label: 'Ionic', hasChildren: false },
|
||||
]
|
||||
break
|
||||
case 'vue':
|
||||
childrenData = [
|
||||
{ value: 'nuxt', label: 'Nuxt.js', hasChildren: false },
|
||||
{ value: 'quasar', label: 'Quasar', hasChildren: false },
|
||||
]
|
||||
break
|
||||
case 'react':
|
||||
childrenData = [
|
||||
{ value: 'nextjs', label: 'Next.js', hasChildren: false },
|
||||
{ value: 'gatsby', label: 'Gatsby', hasChildren: false },
|
||||
]
|
||||
break
|
||||
case 'nodejs':
|
||||
childrenData = [
|
||||
{ value: 'express', label: 'Express.js', hasChildren: false },
|
||||
{ value: 'nestjs', label: 'NestJS', hasChildren: false },
|
||||
{ value: 'fastify', label: 'Fastify', hasChildren: false },
|
||||
]
|
||||
break
|
||||
case 'python':
|
||||
childrenData = [
|
||||
{ value: 'django', label: 'Django', hasChildren: false },
|
||||
{ value: 'fastapi', label: 'FastAPI', hasChildren: false },
|
||||
{ value: 'flask', label: 'Flask', hasChildren: false },
|
||||
]
|
||||
break
|
||||
}
|
||||
|
||||
// Insert data ke dalam tree state
|
||||
const success = findAndInsertChildren(treeData.value, parentId, childrenData)
|
||||
console.log(`[DEMO] Insert children result:`, success)
|
||||
|
||||
// Force trigger reactivity
|
||||
triggerRef(treeData)
|
||||
console.log(`[DEMO] Current tree data:`, JSON.stringify(treeData.value, null, 2))
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="p-10 max-w-2xl mx-auto">
|
||||
<div class="mb-6">
|
||||
<h1 class="mb-2 text-3xl font-bold text-slate-800">Demo: Tree Select dengan Lazy Loading</h1>
|
||||
<p class="text-slate-600">
|
||||
Contoh penggunaan komponen TreeSelect dengan data teknologi.
|
||||
Pilih item untuk melihat sub-kategori yang dimuat secara lazy.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="mb-6 p-4 bg-blue-50 border border-blue-200 rounded-lg">
|
||||
<h3 class="font-semibold text-blue-800 mb-2">💡 Catatan untuk Developer:</h3>
|
||||
<p class="text-sm text-blue-700">
|
||||
Untuk implementasi nyata dengan data divisi rumah sakit,
|
||||
lihat komponen <code class="px-1 bg-blue-100 rounded">content/division/entry.vue</code>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="space-y-4">
|
||||
<div>
|
||||
<label class="block text-sm font-medium text-slate-700 mb-2">
|
||||
Pilih Teknologi:
|
||||
</label>
|
||||
<TreeSelect
|
||||
v-model="selectedValue"
|
||||
:data="treeData"
|
||||
:on-fetch-children="handleFetchChildren"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="p-4 bg-slate-50 rounded-lg">
|
||||
<p class="text-sm text-slate-600 mb-1">Value yang terpilih:</p>
|
||||
<span class="px-3 py-1 font-mono text-sm bg-white border rounded-md">
|
||||
{{ selectedValue || 'Belum ada yang dipilih' }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mt-8 text-xs text-slate-500">
|
||||
<p>🔄 Data dimuat secara lazy saat node parent dibuka</p>
|
||||
<p>⏱️ Simulasi delay 600ms untuk menampilkan loading state</p>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
@@ -0,0 +1,47 @@
|
||||
<script setup lang="ts">
|
||||
import Block from '~/components/pub/form/block.vue'
|
||||
import FieldGroup from '~/components/pub/form/field-group.vue'
|
||||
import Field from '~/components/pub/form/field.vue'
|
||||
import Label from '~/components/pub/form/label.vue'
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<form id="entry-form">
|
||||
<div class="mb-5 border-b border-b-slate-300 pb-3 text-lg xl:text-xl">
|
||||
<Icon name="i-lucide-user" class="me-2" />
|
||||
<span class="font-semibold">Tambah</span> Pasien
|
||||
</div>
|
||||
|
||||
<div class="mb-5 border-b border-b-slate-300 pb-3 text-lg xl:text-xl">
|
||||
<Block>
|
||||
<FieldGroup :column="3">
|
||||
<Label>Nama</Label>
|
||||
<Field>
|
||||
<Input type="text" name="name" />
|
||||
</Field>
|
||||
</FieldGroup>
|
||||
<FieldGroup :column="3">
|
||||
<Label>Nama</Label>
|
||||
<Field>
|
||||
<Input type="text" name="name" />
|
||||
</Field>
|
||||
</FieldGroup>
|
||||
<FieldGroup :column="3">
|
||||
<Label>Nomor RM</Label>
|
||||
<Field>
|
||||
<Input type="text" name="name" />
|
||||
</Field>
|
||||
</FieldGroup>
|
||||
<FieldGroup>
|
||||
<Label dynamic>Alamat</Label>
|
||||
<Field>
|
||||
<Input type="text" name="name" />
|
||||
</Field>
|
||||
</FieldGroup>
|
||||
</Block>
|
||||
</div>
|
||||
<div class="my-2 flex justify-end py-2">
|
||||
<PubNavFooterCsd />
|
||||
</div>
|
||||
</form>
|
||||
</template>
|
||||
@@ -0,0 +1,112 @@
|
||||
import type { Col, KeyLabel, RecComponent, RecStrFuncComponent, RecStrFuncUnknown, Th } from '~/components/pub/my-ui/data/types'
|
||||
import { defineAsyncComponent } from 'vue'
|
||||
|
||||
type SmallDetailDto = any
|
||||
|
||||
const action = defineAsyncComponent(() => import('~/components/pub/my-ui/data/dropdown-action-dud.vue'))
|
||||
|
||||
export const cols: Col[] = [
|
||||
{},
|
||||
{},
|
||||
{},
|
||||
{ width: 100 },
|
||||
{ width: 120 },
|
||||
{},
|
||||
{},
|
||||
{},
|
||||
{ width: 100 },
|
||||
{ width: 100 },
|
||||
{},
|
||||
{ width: 50 },
|
||||
]
|
||||
|
||||
export const header: Th[][] = [
|
||||
[
|
||||
{ label: 'Nama' },
|
||||
{ label: 'Rekam Medis' },
|
||||
{ label: 'KTP' },
|
||||
{ label: 'Tgl Lahir' },
|
||||
{ label: 'Umur' },
|
||||
{ label: 'JK' },
|
||||
{ label: 'Pendidikan' },
|
||||
{ label: 'Status' },
|
||||
{ label: '' },
|
||||
],
|
||||
]
|
||||
|
||||
export const keys = [
|
||||
'name',
|
||||
'medicalRecord_number',
|
||||
'identity_number',
|
||||
'birth_date',
|
||||
'patient_age',
|
||||
'gender',
|
||||
'education',
|
||||
'status',
|
||||
'action',
|
||||
]
|
||||
|
||||
export const delKeyNames: KeyLabel[] = [
|
||||
{ key: 'code', label: 'Kode' },
|
||||
{ key: 'name', label: 'Nama' },
|
||||
]
|
||||
|
||||
export const funcParsed: RecStrFuncUnknown = {
|
||||
name: (rec: unknown): unknown => {
|
||||
const recX = rec as SmallDetailDto
|
||||
return `${recX.firstName} ${recX.middleName || ''} ${recX.lastName || ''}`
|
||||
},
|
||||
identity_number: (rec: unknown): unknown => {
|
||||
const recX = rec as SmallDetailDto
|
||||
if (recX.identity_number?.substring(0, 5) === 'BLANK') {
|
||||
return '(TANPA NIK)'
|
||||
}
|
||||
return recX.identity_number
|
||||
},
|
||||
birth_date: (rec: unknown): unknown => {
|
||||
const recX = rec as SmallDetailDto
|
||||
if (typeof recX.birth_date == 'object' && recX.birth_date) {
|
||||
return (recX.birth_date as Date).toLocaleDateString()
|
||||
} else if (typeof recX.birth_date == 'string') {
|
||||
return (recX.birth_date as string).substring(0, 10)
|
||||
}
|
||||
return recX.birth_date
|
||||
},
|
||||
patient_age: (rec: unknown): unknown => {
|
||||
const recX = rec as SmallDetailDto
|
||||
return recX.birth_date?.split('T')[0]
|
||||
},
|
||||
gender: (rec: unknown): unknown => {
|
||||
const recX = rec as SmallDetailDto
|
||||
if (typeof recX?.gender_code !== 'number' && recX?.gender_code !== '') {
|
||||
return 'Tidak Diketahui'
|
||||
}
|
||||
return recX.gender_code
|
||||
},
|
||||
education: (rec: unknown): unknown => {
|
||||
const recX = rec as SmallDetailDto
|
||||
if (typeof recX.education_code == 'number' && recX.education_code >= 0) {
|
||||
return recX.education_code
|
||||
} else if (typeof recX.education_code) {
|
||||
return recX.education_code
|
||||
}
|
||||
return '-'
|
||||
},
|
||||
}
|
||||
|
||||
export const funcComponent: RecStrFuncComponent = {
|
||||
action(rec, idx) {
|
||||
const res: RecComponent = {
|
||||
idx,
|
||||
rec: rec as object,
|
||||
component: action,
|
||||
}
|
||||
return res
|
||||
},
|
||||
}
|
||||
|
||||
export const funcHtml: RecStrFuncUnknown = {
|
||||
patient_address(_rec) {
|
||||
return '-'
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
<script setup lang="ts">
|
||||
import { cols, funcComponent, funcHtml, funcParsed, header, keys } from './list-cfg'
|
||||
|
||||
defineProps<{
|
||||
data: any[]
|
||||
}>()
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<PubMyUiDataTable
|
||||
:rows="data"
|
||||
:cols="cols"
|
||||
:header="header"
|
||||
:keys="keys"
|
||||
:func-parsed="funcParsed"
|
||||
:func-html="funcHtml"
|
||||
:func-component="funcComponent"
|
||||
/>
|
||||
</template>
|
||||
@@ -0,0 +1,73 @@
|
||||
<script setup lang="ts">
|
||||
import AssesmentFunctionList from './assesment-function/list.vue'
|
||||
|
||||
const props = defineProps<{
|
||||
initialActiveTab: string
|
||||
}>()
|
||||
|
||||
const activeTab = ref(props.initialActiveTab)
|
||||
const emit = defineEmits<{
|
||||
changeTab: [value: string]
|
||||
}>()
|
||||
|
||||
interface TabItem {
|
||||
value: string
|
||||
label: string
|
||||
component?: any
|
||||
props?: Record<string, any>
|
||||
}
|
||||
|
||||
const tabs: TabItem[] = [
|
||||
{ value: 'status', label: 'Status Masuk/Keluar' },
|
||||
{ value: 'early-medical-assessment', label: 'Pengkajian Awal Medis' },
|
||||
{ value: 'rehab-medical-assessment', label: 'Pengkajian Awal Medis Rehabilitasi Medis' },
|
||||
{ value: 'function-assessment', label: 'Asesmen Fungsi', component: AssesmentFunctionList },
|
||||
{ value: 'therapy-protocol', label: 'Protokol Terapi' },
|
||||
{ value: 'education-assessment', label: 'Asesmen Kebutuhan Edukasi' },
|
||||
{ value: 'consent', label: 'General Consent' },
|
||||
{ value: 'patient-note', label: 'CPRJ' },
|
||||
{ value: 'prescription', label: 'Order Obat' },
|
||||
{ value: 'device', label: 'Order Alkes' },
|
||||
{ value: 'mcu-radiology', label: 'Order Radiologi' },
|
||||
{ value: 'mcu-lab-pc', label: 'Order Lab PK' },
|
||||
{ value: 'mcu-lab-micro', label: 'Order Lab Mikro' },
|
||||
{ value: 'mcu-lab-pa', label: 'Order Lab PA' },
|
||||
{ value: 'medical-action', label: 'Order Ruang Tindakan' },
|
||||
{ value: 'mcu-result', label: 'Hasil Penunjang' },
|
||||
{ value: 'consultation', label: 'Konsultasi' },
|
||||
{ value: 'resume', label: 'Resume' },
|
||||
{ value: 'control', label: 'Surat Kontrol' },
|
||||
{ value: 'screening', label: 'Skrinning MPP' },
|
||||
{ value: 'supporting-document', label: 'Upload Dokumen Pendukung' },
|
||||
]
|
||||
|
||||
function changeTab(value: string) {
|
||||
activeTab.value = value;
|
||||
emit('changeTab', value);
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<!-- Tabs -->
|
||||
<div class="mt-4 flex flex-wrap gap-2 rounded-md border bg-white p-4 shadow-sm">
|
||||
<Button
|
||||
v-for="tab in tabs"
|
||||
:key="tab.value"
|
||||
:data-active="activeTab === tab.value"
|
||||
class="rounded-full transition data-[active=false]:bg-gray-100 data-[active=true]:bg-primary data-[active=false]:text-gray-700 data-[active=true]:text-white"
|
||||
@click="changeTab(tab.value)"
|
||||
>
|
||||
{{ tab.label }}
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
<!-- Active Tab Content -->
|
||||
<div class="mt-4 rounded-md border p-4">
|
||||
<component
|
||||
v-if="tabs.find((t) => t.value === activeTab)?.component"
|
||||
:is="tabs.find((t) => t.value === activeTab)?.component"
|
||||
:label="tabs.find((t) => t.value === activeTab)?.label"
|
||||
v-bind="tabs.find((t) => t.value === activeTab)?.props || {}"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
@@ -0,0 +1,181 @@
|
||||
<script setup lang="ts">
|
||||
import type { FormErrors } from '~/types/error'
|
||||
import { toTypedSchema } from '@vee-validate/zod'
|
||||
import Combobox from '~/components/pub/my-ui/form/combobox.vue'
|
||||
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'
|
||||
|
||||
interface SpecialistFormData {
|
||||
name: string
|
||||
code: string
|
||||
installationId: string
|
||||
unitId: string
|
||||
}
|
||||
|
||||
const props = defineProps<{
|
||||
schema: any
|
||||
initialValues?: Partial<SpecialistFormData>
|
||||
errors?: FormErrors
|
||||
installation: {
|
||||
msg: {
|
||||
placeholder: string
|
||||
search: string
|
||||
empty: string
|
||||
}
|
||||
items: {
|
||||
value: string
|
||||
label: string
|
||||
code: string
|
||||
}[]
|
||||
}
|
||||
unit: {
|
||||
msg: {
|
||||
placeholder: string
|
||||
search: string
|
||||
empty: string
|
||||
}
|
||||
items: {
|
||||
value: string
|
||||
label: string
|
||||
code: string
|
||||
}[]
|
||||
}
|
||||
}>()
|
||||
|
||||
const emit = defineEmits<{
|
||||
'submit': [values: SpecialistFormData, resetForm: () => void]
|
||||
'cancel': [resetForm: () => void]
|
||||
'installationChanged': [id: string]
|
||||
}>()
|
||||
|
||||
const formSchema = toTypedSchema(props.schema)
|
||||
|
||||
// Form submission handler
|
||||
function onSubmitForm(values: any, { resetForm }: { resetForm: () => void }) {
|
||||
const formData: SpecialistFormData = {
|
||||
name: values.name || '',
|
||||
code: values.code || '',
|
||||
installationId: values.installationId || '',
|
||||
unitId: values.unitId || '',
|
||||
}
|
||||
emit('submit', formData, resetForm)
|
||||
}
|
||||
|
||||
// Form cancel handler
|
||||
function onCancelForm({ resetForm }: { resetForm: () => void }) {
|
||||
emit('cancel', resetForm)
|
||||
}
|
||||
|
||||
// Watch for installation changes
|
||||
function onInstallationChanged(installationId: string, setFieldValue: any) {
|
||||
setFieldValue('unitId', '', false)
|
||||
emit('installationChanged', installationId || '')
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Form
|
||||
v-slot="{ handleSubmit, resetForm, values, setFieldValue }" as="" keep-values :validation-schema="formSchema"
|
||||
:initial-values="initialValues"
|
||||
>
|
||||
<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">
|
||||
<FieldGroup>
|
||||
<Label label-for="name">Nama</Label>
|
||||
<Field id="name" :errors="errors">
|
||||
<FormField v-slot="{ componentField }" name="name">
|
||||
<FormItem>
|
||||
<FormControl>
|
||||
<Input
|
||||
id="name"
|
||||
type="text"
|
||||
placeholder="Masukkan nama spesialisasi"
|
||||
autocomplete="off"
|
||||
v-bind="componentField"
|
||||
/>
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
</FormField>
|
||||
</Field>
|
||||
</FieldGroup>
|
||||
|
||||
<FieldGroup>
|
||||
<Label label-for="code">Kode</Label>
|
||||
<Field id="code" :errors="errors">
|
||||
<FormField v-slot="{ componentField }" name="code">
|
||||
<FormItem>
|
||||
<FormControl>
|
||||
<Input
|
||||
id="code"
|
||||
type="text"
|
||||
placeholder="Masukkan kode spesialisasi"
|
||||
autocomplete="off"
|
||||
v-bind="componentField"
|
||||
/>
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
</FormField>
|
||||
</Field>
|
||||
</FieldGroup>
|
||||
|
||||
<FieldGroup>
|
||||
<Label label-for="installationId">Instalasi</Label>
|
||||
<Field id="installationId" :errors="errors">
|
||||
<FormField v-slot="{ componentField }" name="installationId">
|
||||
<FormItem>
|
||||
<FormControl>
|
||||
<Combobox
|
||||
id="installationId"
|
||||
v-bind="componentField"
|
||||
:items="installation.items"
|
||||
:placeholder="installation.msg.placeholder"
|
||||
:search-placeholder="installation.msg.search"
|
||||
:empty-message="installation.msg.empty"
|
||||
@update:model-value="(value) => onInstallationChanged(value, setFieldValue)"
|
||||
/>
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
</FormField>
|
||||
</Field>
|
||||
</FieldGroup>
|
||||
|
||||
<FieldGroup>
|
||||
<Label label-for="unitId">Unit</Label>
|
||||
<Field id="unitId" :errors="errors">
|
||||
<FormField v-slot="{ componentField }" name="unitId">
|
||||
<FormItem>
|
||||
<FormControl>
|
||||
<Combobox
|
||||
id="unitId"
|
||||
:disabled="!values.installationId"
|
||||
v-bind="componentField"
|
||||
:items="unit.items"
|
||||
:placeholder="unit.msg.placeholder"
|
||||
:search-placeholder="unit.msg.search"
|
||||
:empty-message="unit.msg.empty"
|
||||
/>
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
</FormField>
|
||||
</Field>
|
||||
</FieldGroup>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="flex justify-end gap-2 mt-4">
|
||||
<Button type="button" variant="outline" @click="onCancelForm({ resetForm })">
|
||||
Batal
|
||||
</Button>
|
||||
<Button type="submit">
|
||||
Simpan
|
||||
</Button>
|
||||
</div>
|
||||
</form>
|
||||
</Form>
|
||||
</template>
|
||||
@@ -0,0 +1,213 @@
|
||||
<script setup lang="ts">
|
||||
import type { FormErrors } from '~/types/error'
|
||||
import { toTypedSchema } from '@vee-validate/zod'
|
||||
import Combobox from '~/components/pub/my-ui/form/combobox.vue'
|
||||
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'
|
||||
|
||||
interface SubSpecialistFormData {
|
||||
name: string
|
||||
code: string
|
||||
installationId: string
|
||||
unitId: string
|
||||
specialistId: string
|
||||
}
|
||||
|
||||
const props = defineProps<{
|
||||
schema: any
|
||||
initialValues?: Partial<SubSpecialistFormData>
|
||||
errors?: FormErrors
|
||||
installation: {
|
||||
msg: {
|
||||
placeholder: string
|
||||
search: string
|
||||
empty: string
|
||||
}
|
||||
items: {
|
||||
value: string
|
||||
label: string
|
||||
code: string
|
||||
}[]
|
||||
}
|
||||
unit: {
|
||||
msg: {
|
||||
placeholder: string
|
||||
search: string
|
||||
empty: string
|
||||
}
|
||||
items: {
|
||||
value: string
|
||||
label: string
|
||||
code: string
|
||||
}[]
|
||||
}
|
||||
specialist: {
|
||||
msg: {
|
||||
placeholder: string
|
||||
search: string
|
||||
empty: string
|
||||
}
|
||||
items: {
|
||||
value: string
|
||||
label: string
|
||||
code: string
|
||||
}[]
|
||||
}
|
||||
}>()
|
||||
|
||||
const emit = defineEmits<{
|
||||
'submit': [values: SubSpecialistFormData, resetForm: () => void]
|
||||
'cancel': [resetForm: () => void]
|
||||
'installationChanged': [id: string]
|
||||
'unitChanged': [id: string]
|
||||
}>()
|
||||
|
||||
const formSchema = toTypedSchema(props.schema)
|
||||
|
||||
// Form submission handler
|
||||
function onSubmitForm(values: any, { resetForm }: { resetForm: () => void }) {
|
||||
const formData: SubSpecialistFormData = {
|
||||
name: values.name || '',
|
||||
code: values.code || '',
|
||||
installationId: values.installationId || '',
|
||||
unitId: values.unitId || '',
|
||||
specialistId: values.specialistId || '',
|
||||
}
|
||||
emit('submit', formData, resetForm)
|
||||
}
|
||||
|
||||
// Form cancel handler
|
||||
function onCancelForm({ resetForm }: { resetForm: () => void }) {
|
||||
emit('cancel', resetForm)
|
||||
}
|
||||
|
||||
// Watch for installation changes
|
||||
function onInstallationChanged(installationId: string, setFieldValue: any) {
|
||||
setFieldValue('unitId', '', false)
|
||||
setFieldValue('specialistId', '', false)
|
||||
emit('installationChanged', installationId || '')
|
||||
}
|
||||
|
||||
function onUnitChanged(unitId: string, setFieldValue: any) {
|
||||
setFieldValue('specialistId', '', false)
|
||||
emit('unitChanged', unitId || '')
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Form
|
||||
v-slot="{
|
||||
handleSubmit,
|
||||
resetForm,
|
||||
values,
|
||||
setFieldValue,
|
||||
}" as="" keep-values :validation-schema="formSchema"
|
||||
:initial-values="initialValues"
|
||||
>
|
||||
<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">
|
||||
<FieldGroup>
|
||||
<Label label-for="name">Nama</Label>
|
||||
<Field id="name" :errors="errors">
|
||||
<FormField v-slot="{ componentField }" name="name">
|
||||
<FormItem>
|
||||
<FormControl>
|
||||
<Input
|
||||
id="name" type="text" placeholder="Masukkan nama spesialisasi" autocomplete="off"
|
||||
v-bind="componentField"
|
||||
/>
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
</FormField>
|
||||
</Field>
|
||||
</FieldGroup>
|
||||
|
||||
<FieldGroup>
|
||||
<Label label-for="code">Kode</Label>
|
||||
<Field id="code" :errors="errors">
|
||||
<FormField v-slot="{ componentField }" name="code">
|
||||
<FormItem>
|
||||
<FormControl>
|
||||
<Input
|
||||
id="code" type="text" placeholder="Masukkan kode spesialisasi" autocomplete="off"
|
||||
v-bind="componentField"
|
||||
/>
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
</FormField>
|
||||
</Field>
|
||||
</FieldGroup>
|
||||
|
||||
<FieldGroup>
|
||||
<Label label-for="installationId">Instalasi</Label>
|
||||
<Field id="installationId" :errors="errors">
|
||||
<FormField v-slot="{ componentField }" name="installationId">
|
||||
<FormItem>
|
||||
<FormControl>
|
||||
<Combobox
|
||||
id="installationId" v-bind="componentField" :items="installation.items"
|
||||
:placeholder="installation.msg.placeholder" :search-placeholder="installation.msg.search"
|
||||
:empty-message="installation.msg.empty"
|
||||
@update:model-value="(value) => onInstallationChanged(value, setFieldValue)"
|
||||
/>
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
</FormField>
|
||||
</Field>
|
||||
</FieldGroup>
|
||||
|
||||
<FieldGroup>
|
||||
<Label label-for="unitId">Unit</Label>
|
||||
<Field id="unitId" :errors="errors">
|
||||
<FormField v-slot="{ componentField }" name="unitId">
|
||||
<FormItem>
|
||||
<FormControl>
|
||||
<Combobox
|
||||
id="unitId" :disabled="!values.installationId" v-bind="componentField" :items="unit.items"
|
||||
:placeholder="unit.msg.placeholder" :search-placeholder="unit.msg.search"
|
||||
:empty-message="unit.msg.empty"
|
||||
@update:model-value="(value) => onUnitChanged(value, setFieldValue)"
|
||||
/>
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
</FormField>
|
||||
</Field>
|
||||
</FieldGroup>
|
||||
|
||||
<FieldGroup>
|
||||
<Label label-for="specialistId">Specialist</Label>
|
||||
<Field id="specialistId" :errors="errors">
|
||||
<FormField v-slot="{ componentField }" name="specialistId">
|
||||
<FormItem>
|
||||
<FormControl>
|
||||
<Combobox
|
||||
id="specialistId" :disabled="!values.unitId" v-bind="componentField" :items="specialist.items"
|
||||
:placeholder="specialist.msg.placeholder" :search-placeholder="specialist.msg.search"
|
||||
:empty-message="specialist.msg.empty"
|
||||
/>
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
</FormField>
|
||||
</Field>
|
||||
</FieldGroup>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="flex justify-end gap-2 mt-4">
|
||||
<Button type="button" variant="outline" @click="onCancelForm({ resetForm })">
|
||||
Batal
|
||||
</Button>
|
||||
<Button type="submit">
|
||||
Simpan
|
||||
</Button>
|
||||
</div>
|
||||
</form>
|
||||
</Form>
|
||||
</template>
|
||||
@@ -0,0 +1,125 @@
|
||||
<script setup lang="ts">
|
||||
import type { FormErrors } from '~/types/error'
|
||||
import { toTypedSchema } from '@vee-validate/zod'
|
||||
import Combobox from '~/components/pub/my-ui/form/combobox.vue'
|
||||
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'
|
||||
|
||||
interface UnitFormData {
|
||||
name: string
|
||||
code: string
|
||||
parentId: string
|
||||
}
|
||||
|
||||
const props = defineProps<{
|
||||
unit: {
|
||||
msg: {
|
||||
placeholder: string
|
||||
search: string
|
||||
empty: string
|
||||
}
|
||||
items: {
|
||||
value: string
|
||||
label: string
|
||||
code: string
|
||||
}[]
|
||||
}
|
||||
schema: any
|
||||
initialValues?: Partial<UnitFormData>
|
||||
errors?: FormErrors
|
||||
}>()
|
||||
|
||||
const emit = defineEmits<{
|
||||
'submit': [values: UnitFormData, resetForm: () => void]
|
||||
'cancel': [resetForm: () => void]
|
||||
}>()
|
||||
|
||||
const formSchema = toTypedSchema(props.schema)
|
||||
|
||||
// Form submission handler
|
||||
function onSubmitForm(values: any, { resetForm }: { resetForm: () => void }) {
|
||||
const formData: UnitFormData = {
|
||||
name: values.name || '',
|
||||
code: values.code || '',
|
||||
parentId: values.parentId || '',
|
||||
}
|
||||
emit('submit', formData, resetForm)
|
||||
}
|
||||
|
||||
// Form cancel handler
|
||||
function onCancelForm({ resetForm }: { resetForm: () => void }) {
|
||||
emit('cancel', resetForm)
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Form
|
||||
v-slot="{ handleSubmit, resetForm }" as="" keep-values :validation-schema="formSchema"
|
||||
:initial-values="initialValues"
|
||||
>
|
||||
<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">
|
||||
<FieldGroup>
|
||||
<Label label-for="name">Nama</Label>
|
||||
<Field id="name" :errors="errors">
|
||||
<FormField v-slot="{ componentField }" name="name">
|
||||
<FormItem>
|
||||
<FormControl>
|
||||
<Input
|
||||
id="name" type="text" placeholder="Masukkan nama unit" autocomplete="off"
|
||||
v-bind="componentField"
|
||||
/>
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
</FormField>
|
||||
</Field>
|
||||
</FieldGroup>
|
||||
|
||||
<FieldGroup>
|
||||
<Label label-for="code">Kode</Label>
|
||||
<Field id="code" :errors="errors">
|
||||
<FormField v-slot="{ componentField }" name="code">
|
||||
<FormItem>
|
||||
<FormControl>
|
||||
<Input id="code" type="text" placeholder="Masukkan kode unit" autocomplete="off" v-bind="componentField" />
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
</FormField>
|
||||
</Field>
|
||||
</FieldGroup>
|
||||
|
||||
<FieldGroup>
|
||||
<Label label-for="parentId">Instalasi</Label>
|
||||
<Field id="parentId" :errors="errors">
|
||||
<FormField v-slot="{ componentField }" name="parentId">
|
||||
<FormItem>
|
||||
<FormControl>
|
||||
<Combobox
|
||||
id="parentId" v-bind="componentField" :items="unit.items"
|
||||
:placeholder="unit.msg.placeholder" :search-placeholder="unit.msg.search"
|
||||
:empty-message="unit.msg.empty"
|
||||
/>
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
</FormField>
|
||||
</Field>
|
||||
</FieldGroup>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="flex justify-end gap-2 mt-4">
|
||||
<Button type="button" variant="outline" @click="onCancelForm({ resetForm })">
|
||||
Batal
|
||||
</Button>
|
||||
<Button type="submit">
|
||||
Simpan
|
||||
</Button>
|
||||
</div>
|
||||
</form>
|
||||
</Form>
|
||||
</template>
|
||||
Reference in New Issue
Block a user