Merge branch 'dev' into fe-prescription-56
This commit is contained in:
@@ -174,7 +174,7 @@ body {
|
|||||||
}
|
}
|
||||||
|
|
||||||
body, table, label {
|
body, table, label {
|
||||||
@apply md:!text-xs xl:!text-sm 2xl:!text-sm;
|
@apply md:!text-xs 2xl:!text-sm;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Container */
|
/* Container */
|
||||||
|
|||||||
@@ -5,6 +5,10 @@ import Cell from '~/components/pub/my-ui/doc-entry/cell.vue'
|
|||||||
import Field from '~/components/pub/my-ui/doc-entry/field.vue'
|
import Field from '~/components/pub/my-ui/doc-entry/field.vue'
|
||||||
import Label from '~/components/pub/my-ui/doc-entry/label.vue'
|
import Label from '~/components/pub/my-ui/doc-entry/label.vue'
|
||||||
import Button from '~/components/pub/ui/button/Button.vue'
|
import Button from '~/components/pub/ui/button/Button.vue'
|
||||||
|
import Combobox from '~/components/pub/my-ui/combobox/combobox.vue'
|
||||||
|
|
||||||
|
// Constants
|
||||||
|
import { infraGroupCodesKeys } from '~/lib/constants'
|
||||||
|
|
||||||
// Types
|
// Types
|
||||||
import type { InfraFormData } from '~/schemas/infra.schema'
|
import type { InfraFormData } from '~/schemas/infra.schema'
|
||||||
@@ -16,6 +20,7 @@ import { toTypedSchema } from '@vee-validate/zod'
|
|||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
schema: z.ZodSchema<any>
|
schema: z.ZodSchema<any>
|
||||||
|
parents: any[]
|
||||||
values: any
|
values: any
|
||||||
isLoading?: boolean
|
isLoading?: boolean
|
||||||
isReadonly?: boolean
|
isReadonly?: boolean
|
||||||
@@ -34,27 +39,28 @@ const { defineField, errors, meta } = useForm({
|
|||||||
initialValues: {
|
initialValues: {
|
||||||
code: '',
|
code: '',
|
||||||
name: '',
|
name: '',
|
||||||
infraGroup_code: 'counter',
|
infraGroup_code: infraGroupCodesKeys.bed,
|
||||||
parent_id: null,
|
parent_id: null,
|
||||||
} as Partial<InfraFormData>,
|
} as Partial<InfraFormData>,
|
||||||
})
|
})
|
||||||
|
|
||||||
const [code, codeAttrs] = defineField('code')
|
const [code, codeAttrs] = defineField('code')
|
||||||
const [name, nameAttrs] = defineField('name')
|
const [name, nameAttrs] = defineField('name')
|
||||||
const [infraGroup_code, infraGroupAttrs] = defineField('infraGroup_code')
|
const [infraGroup_code] = defineField('infraGroup_code')
|
||||||
const [parent_id, parentIdAttrs] = defineField('parent_id')
|
const [parent_id, parentIdAttrs] = defineField('parent_id')
|
||||||
|
|
||||||
if (props.values) {
|
if (props.values) {
|
||||||
if (props.values.code !== undefined) code.value = props.values.code
|
if (props.values.code !== undefined) code.value = props.values.code
|
||||||
if (props.values.name !== undefined) name.value = props.values.name
|
if (props.values.name !== undefined) name.value = props.values.name
|
||||||
if (props.values.infraGroup_code !== undefined) infraGroup_code.value = props.values.infraGroup_code
|
if (props.values.infraGroup_code !== undefined) infraGroup_code.value = props.values.infraGroup_code
|
||||||
if (props.values.parent_id !== undefined) parent_id.value = props.values.parent_id
|
if (props.values.parent_id !== undefined)
|
||||||
|
parent_id.value = props.values.parent_id ? Number(props.values.parent_id) : null
|
||||||
}
|
}
|
||||||
|
|
||||||
const resetForm = () => {
|
const resetForm = () => {
|
||||||
code.value = ''
|
code.value = ''
|
||||||
name.value = ''
|
name.value = ''
|
||||||
infraGroup_code.value = 'counter'
|
infraGroup_code.value = infraGroupCodesKeys.bed
|
||||||
parent_id.value = null
|
parent_id.value = null
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -62,8 +68,8 @@ function onSubmitForm() {
|
|||||||
const formData: InfraFormData = {
|
const formData: InfraFormData = {
|
||||||
code: code.value || '',
|
code: code.value || '',
|
||||||
name: name.value || '',
|
name: name.value || '',
|
||||||
infraGroup_code: infraGroup_code.value || 'counter',
|
infraGroup_code: infraGroup_code.value || infraGroupCodesKeys.bed,
|
||||||
parent_id: parent_id.value || null,
|
parent_id: parent_id.value ? Number(parent_id.value) : null,
|
||||||
}
|
}
|
||||||
emit('submit', formData, resetForm)
|
emit('submit', formData, resetForm)
|
||||||
}
|
}
|
||||||
@@ -74,23 +80,62 @@ function onCancelForm() {
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<form id="form-counter" @submit.prevent>
|
<form
|
||||||
<Block labelSize="thin" class="!mb-2.5 !pt-0 xl:!mb-3" :colCount="1">
|
id="form-floor"
|
||||||
|
@submit.prevent
|
||||||
|
>
|
||||||
|
<Block
|
||||||
|
labelSize="thin"
|
||||||
|
class="!mb-2.5 !pt-0 xl:!mb-3"
|
||||||
|
:colCount="1"
|
||||||
|
>
|
||||||
<Cell>
|
<Cell>
|
||||||
<Label height="compact">Kode</Label>
|
<Label height="compact">Kode</Label>
|
||||||
<Field :errMessage="errors.code">
|
<Field :errMessage="errors.code">
|
||||||
<Input id="code" v-model="code" v-bind="codeAttrs" :disabled="isLoading || isReadonly" />
|
<Input
|
||||||
|
id="code"
|
||||||
|
v-model="code"
|
||||||
|
v-bind="codeAttrs"
|
||||||
|
:disabled="isLoading || isReadonly"
|
||||||
|
/>
|
||||||
</Field>
|
</Field>
|
||||||
</Cell>
|
</Cell>
|
||||||
<Cell>
|
<Cell>
|
||||||
<Label height="compact">Nama</Label>
|
<Label height="compact">Nama</Label>
|
||||||
<Field :errMessage="errors.name">
|
<Field :errMessage="errors.name">
|
||||||
<Input id="name" v-model="name" v-bind="nameAttrs" :disabled="isLoading || isReadonly" />
|
<Input
|
||||||
|
id="name"
|
||||||
|
v-model="name"
|
||||||
|
v-bind="nameAttrs"
|
||||||
|
:disabled="isLoading || isReadonly"
|
||||||
|
/>
|
||||||
|
</Field>
|
||||||
|
</Cell>
|
||||||
|
<Cell>
|
||||||
|
<Label height="compact">Kamar</Label>
|
||||||
|
<Field :errMessage="errors.parent_id">
|
||||||
|
<Combobox
|
||||||
|
id="parent"
|
||||||
|
v-model="parent_id"
|
||||||
|
v-bind="parentIdAttrs"
|
||||||
|
:items="parents"
|
||||||
|
:is-disabled="isLoading || isReadonly"
|
||||||
|
placeholder="Pilih Kamar"
|
||||||
|
search-placeholder="Cari Kamar"
|
||||||
|
empty-message="Item tidak ditemukan"
|
||||||
|
/>
|
||||||
</Field>
|
</Field>
|
||||||
</Cell>
|
</Cell>
|
||||||
</Block>
|
</Block>
|
||||||
<div class="my-2 flex justify-end gap-2 py-2">
|
<div class="my-2 flex justify-end gap-2 py-2">
|
||||||
<Button type="button" variant="secondary" class="w-[120px]" @click="onCancelForm"> Kembali </Button>
|
<Button
|
||||||
|
type="button"
|
||||||
|
variant="secondary"
|
||||||
|
class="w-[120px]"
|
||||||
|
@click="onCancelForm"
|
||||||
|
>
|
||||||
|
Kembali
|
||||||
|
</Button>
|
||||||
<Button
|
<Button
|
||||||
v-if="!isReadonly"
|
v-if="!isReadonly"
|
||||||
type="button"
|
type="button"
|
||||||
|
|||||||
@@ -12,9 +12,9 @@ type SmallDetailDto = any
|
|||||||
|
|
||||||
const action = defineAsyncComponent(() => import('~/components/pub/my-ui/data/dropdown-action-dud.vue'))
|
const action = defineAsyncComponent(() => import('~/components/pub/my-ui/data/dropdown-action-dud.vue'))
|
||||||
|
|
||||||
export const cols: Col[] = [{ width: 100 }, {}, {}, { width: 50 }]
|
export const cols: Col[] = [{}, {}, {}, { width: 50 }]
|
||||||
|
|
||||||
export const header: Th[][] = [[{ label: 'Kode' }, { label: 'Nama' }, { label: 'Counter Induk' }, { label: '' }]]
|
export const header: Th[][] = [[{ label: 'Kode' }, { label: 'Nama' }, { label: 'Kamar' }, { label: '' }]]
|
||||||
|
|
||||||
export const keys = ['code', 'name', 'parent', 'action']
|
export const keys = ['code', 'name', 'parent', 'action']
|
||||||
|
|
||||||
@@ -36,9 +36,6 @@ export const funcComponent: RecStrFuncComponent = {
|
|||||||
idx,
|
idx,
|
||||||
rec: rec as object,
|
rec: rec as object,
|
||||||
component: action,
|
component: action,
|
||||||
props: {
|
|
||||||
size: 'sm',
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
return res
|
return res
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1,6 +1,11 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import type { PaginationMeta } from '~/components/pub/my-ui/pagination/pagination.type'
|
// Components
|
||||||
import PaginationView from '~/components/pub/my-ui/pagination/pagination-view.vue'
|
import PaginationView from '~/components/pub/my-ui/pagination/pagination-view.vue'
|
||||||
|
|
||||||
|
// Types
|
||||||
|
import type { PaginationMeta } from '~/components/pub/my-ui/pagination/pagination.type'
|
||||||
|
|
||||||
|
// Configs
|
||||||
import { cols, funcComponent, funcHtml, funcParsed, header, keys } from './list-cfg'
|
import { cols, funcComponent, funcHtml, funcParsed, header, keys } from './list-cfg'
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
@@ -21,7 +26,7 @@ function handlePageChange(page: number) {
|
|||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="space-y-4">
|
<div class="space-y-4">
|
||||||
<PubBaseDataTable
|
<PubMyUiDataTable
|
||||||
:rows="data"
|
:rows="data"
|
||||||
:cols="cols"
|
:cols="cols"
|
||||||
:header="header"
|
:header="header"
|
||||||
|
|||||||
@@ -5,6 +5,10 @@ import Cell from '~/components/pub/my-ui/doc-entry/cell.vue'
|
|||||||
import Field from '~/components/pub/my-ui/doc-entry/field.vue'
|
import Field from '~/components/pub/my-ui/doc-entry/field.vue'
|
||||||
import Label from '~/components/pub/my-ui/doc-entry/label.vue'
|
import Label from '~/components/pub/my-ui/doc-entry/label.vue'
|
||||||
import Button from '~/components/pub/ui/button/Button.vue'
|
import Button from '~/components/pub/ui/button/Button.vue'
|
||||||
|
import Combobox from '~/components/pub/my-ui/combobox/combobox.vue'
|
||||||
|
|
||||||
|
// Constants
|
||||||
|
import { infraGroupCodesKeys } from '~/lib/constants'
|
||||||
|
|
||||||
// Types
|
// Types
|
||||||
import type { InfraFormData } from '~/schemas/infra.schema'
|
import type { InfraFormData } from '~/schemas/infra.schema'
|
||||||
@@ -16,6 +20,7 @@ import { toTypedSchema } from '@vee-validate/zod'
|
|||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
schema: z.ZodSchema<any>
|
schema: z.ZodSchema<any>
|
||||||
|
parents: any[]
|
||||||
values: any
|
values: any
|
||||||
isLoading?: boolean
|
isLoading?: boolean
|
||||||
isReadonly?: boolean
|
isReadonly?: boolean
|
||||||
@@ -34,27 +39,28 @@ const { defineField, errors, meta } = useForm({
|
|||||||
initialValues: {
|
initialValues: {
|
||||||
code: '',
|
code: '',
|
||||||
name: '',
|
name: '',
|
||||||
infraGroup_code: 'counter',
|
infraGroup_code: infraGroupCodesKeys.chamber,
|
||||||
parent_id: null,
|
parent_id: null,
|
||||||
} as Partial<InfraFormData>,
|
} as Partial<InfraFormData>,
|
||||||
})
|
})
|
||||||
|
|
||||||
const [code, codeAttrs] = defineField('code')
|
const [code, codeAttrs] = defineField('code')
|
||||||
const [name, nameAttrs] = defineField('name')
|
const [name, nameAttrs] = defineField('name')
|
||||||
const [infraGroup_code, infraGroupAttrs] = defineField('infraGroup_code')
|
const [infraGroup_code] = defineField('infraGroup_code')
|
||||||
const [parent_id, parentIdAttrs] = defineField('parent_id')
|
const [parent_id, parentIdAttrs] = defineField('parent_id')
|
||||||
|
|
||||||
if (props.values) {
|
if (props.values) {
|
||||||
if (props.values.code !== undefined) code.value = props.values.code
|
if (props.values.code !== undefined) code.value = props.values.code
|
||||||
if (props.values.name !== undefined) name.value = props.values.name
|
if (props.values.name !== undefined) name.value = props.values.name
|
||||||
if (props.values.infraGroup_code !== undefined) infraGroup_code.value = props.values.infraGroup_code
|
if (props.values.infraGroup_code !== undefined) infraGroup_code.value = props.values.infraGroup_code
|
||||||
if (props.values.parent_id !== undefined) parent_id.value = props.values.parent_id
|
if (props.values.parent_id !== undefined)
|
||||||
|
parent_id.value = props.values.parent_id ? Number(props.values.parent_id) : null
|
||||||
}
|
}
|
||||||
|
|
||||||
const resetForm = () => {
|
const resetForm = () => {
|
||||||
code.value = ''
|
code.value = ''
|
||||||
name.value = ''
|
name.value = ''
|
||||||
infraGroup_code.value = 'counter'
|
infraGroup_code.value = infraGroupCodesKeys.chamber
|
||||||
parent_id.value = null
|
parent_id.value = null
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -62,8 +68,8 @@ function onSubmitForm() {
|
|||||||
const formData: InfraFormData = {
|
const formData: InfraFormData = {
|
||||||
code: code.value || '',
|
code: code.value || '',
|
||||||
name: name.value || '',
|
name: name.value || '',
|
||||||
infraGroup_code: infraGroup_code.value || 'counter',
|
infraGroup_code: infraGroup_code.value || infraGroupCodesKeys.chamber,
|
||||||
parent_id: parent_id.value || null,
|
parent_id: parent_id.value ? Number(parent_id.value) : null,
|
||||||
}
|
}
|
||||||
emit('submit', formData, resetForm)
|
emit('submit', formData, resetForm)
|
||||||
}
|
}
|
||||||
@@ -74,23 +80,62 @@ function onCancelForm() {
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<form id="form-counter" @submit.prevent>
|
<form
|
||||||
<Block labelSize="thin" class="!mb-2.5 !pt-0 xl:!mb-3" :colCount="1">
|
id="form-floor"
|
||||||
|
@submit.prevent
|
||||||
|
>
|
||||||
|
<Block
|
||||||
|
labelSize="thin"
|
||||||
|
class="!mb-2.5 !pt-0 xl:!mb-3"
|
||||||
|
:colCount="1"
|
||||||
|
>
|
||||||
<Cell>
|
<Cell>
|
||||||
<Label height="compact">Kode</Label>
|
<Label height="compact">Kode</Label>
|
||||||
<Field :errMessage="errors.code">
|
<Field :errMessage="errors.code">
|
||||||
<Input id="code" v-model="code" v-bind="codeAttrs" :disabled="isLoading || isReadonly" />
|
<Input
|
||||||
|
id="code"
|
||||||
|
v-model="code"
|
||||||
|
v-bind="codeAttrs"
|
||||||
|
:disabled="isLoading || isReadonly"
|
||||||
|
/>
|
||||||
</Field>
|
</Field>
|
||||||
</Cell>
|
</Cell>
|
||||||
<Cell>
|
<Cell>
|
||||||
<Label height="compact">Nama</Label>
|
<Label height="compact">Nama</Label>
|
||||||
<Field :errMessage="errors.name">
|
<Field :errMessage="errors.name">
|
||||||
<Input id="name" v-model="name" v-bind="nameAttrs" :disabled="isLoading || isReadonly" />
|
<Input
|
||||||
|
id="name"
|
||||||
|
v-model="name"
|
||||||
|
v-bind="nameAttrs"
|
||||||
|
:disabled="isLoading || isReadonly"
|
||||||
|
/>
|
||||||
|
</Field>
|
||||||
|
</Cell>
|
||||||
|
<Cell>
|
||||||
|
<Label height="compact">Lantai</Label>
|
||||||
|
<Field :errMessage="errors.parent_id">
|
||||||
|
<Combobox
|
||||||
|
id="parent"
|
||||||
|
v-model="parent_id"
|
||||||
|
v-bind="parentIdAttrs"
|
||||||
|
:items="parents"
|
||||||
|
:is-disabled="isLoading || isReadonly"
|
||||||
|
placeholder="Pilih Lantai"
|
||||||
|
search-placeholder="Cari Lantai"
|
||||||
|
empty-message="Item tidak ditemukan"
|
||||||
|
/>
|
||||||
</Field>
|
</Field>
|
||||||
</Cell>
|
</Cell>
|
||||||
</Block>
|
</Block>
|
||||||
<div class="my-2 flex justify-end gap-2 py-2">
|
<div class="my-2 flex justify-end gap-2 py-2">
|
||||||
<Button type="button" variant="secondary" class="w-[120px]" @click="onCancelForm"> Kembali </Button>
|
<Button
|
||||||
|
type="button"
|
||||||
|
variant="secondary"
|
||||||
|
class="w-[120px]"
|
||||||
|
@click="onCancelForm"
|
||||||
|
>
|
||||||
|
Kembali
|
||||||
|
</Button>
|
||||||
<Button
|
<Button
|
||||||
v-if="!isReadonly"
|
v-if="!isReadonly"
|
||||||
type="button"
|
type="button"
|
||||||
|
|||||||
@@ -12,9 +12,9 @@ type SmallDetailDto = any
|
|||||||
|
|
||||||
const action = defineAsyncComponent(() => import('~/components/pub/my-ui/data/dropdown-action-dud.vue'))
|
const action = defineAsyncComponent(() => import('~/components/pub/my-ui/data/dropdown-action-dud.vue'))
|
||||||
|
|
||||||
export const cols: Col[] = [{ width: 100 }, {}, {}, { width: 50 }]
|
export const cols: Col[] = [{}, {}, {}, { width: 50 }]
|
||||||
|
|
||||||
export const header: Th[][] = [[{ label: 'Kode' }, { label: 'Nama' }, { label: 'Counter Induk' }, { label: '' }]]
|
export const header: Th[][] = [[{ label: 'Kode' }, { label: 'Nama' }, { label: 'Lantai' }, { label: '' }]]
|
||||||
|
|
||||||
export const keys = ['code', 'name', 'parent', 'action']
|
export const keys = ['code', 'name', 'parent', 'action']
|
||||||
|
|
||||||
@@ -36,9 +36,6 @@ export const funcComponent: RecStrFuncComponent = {
|
|||||||
idx,
|
idx,
|
||||||
rec: rec as object,
|
rec: rec as object,
|
||||||
component: action,
|
component: action,
|
||||||
props: {
|
|
||||||
size: 'sm',
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
return res
|
return res
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1,6 +1,11 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import type { PaginationMeta } from '~/components/pub/my-ui/pagination/pagination.type'
|
// Components
|
||||||
import PaginationView from '~/components/pub/my-ui/pagination/pagination-view.vue'
|
import PaginationView from '~/components/pub/my-ui/pagination/pagination-view.vue'
|
||||||
|
|
||||||
|
// Types
|
||||||
|
import type { PaginationMeta } from '~/components/pub/my-ui/pagination/pagination.type'
|
||||||
|
|
||||||
|
// Configs
|
||||||
import { cols, funcComponent, funcHtml, funcParsed, header, keys } from './list-cfg'
|
import { cols, funcComponent, funcHtml, funcParsed, header, keys } from './list-cfg'
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
@@ -21,7 +26,7 @@ function handlePageChange(page: number) {
|
|||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="space-y-4">
|
<div class="space-y-4">
|
||||||
<PubBaseDataTable
|
<PubMyUiDataTable
|
||||||
:rows="data"
|
:rows="data"
|
||||||
:cols="cols"
|
:cols="cols"
|
||||||
:header="header"
|
:header="header"
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ const { defineField, errors, meta } = useForm({
|
|||||||
initialValues: {
|
initialValues: {
|
||||||
code: '',
|
code: '',
|
||||||
name: '',
|
name: '',
|
||||||
infraGroup_code: infraGroupCodesKeys.building,
|
infraGroup_code: infraGroupCodesKeys.counter,
|
||||||
parent_id: null,
|
parent_id: null,
|
||||||
} as Partial<InfraFormData>,
|
} as Partial<InfraFormData>,
|
||||||
})
|
})
|
||||||
@@ -57,7 +57,7 @@ if (props.values) {
|
|||||||
const resetForm = () => {
|
const resetForm = () => {
|
||||||
code.value = ''
|
code.value = ''
|
||||||
name.value = ''
|
name.value = ''
|
||||||
infraGroup_code.value = infraGroupCodesKeys.building
|
infraGroup_code.value = infraGroupCodesKeys.counter
|
||||||
parent_id.value = null
|
parent_id.value = null
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -65,7 +65,7 @@ function onSubmitForm() {
|
|||||||
const formData: InfraFormData = {
|
const formData: InfraFormData = {
|
||||||
code: code.value || '',
|
code: code.value || '',
|
||||||
name: name.value || '',
|
name: name.value || '',
|
||||||
infraGroup_code: infraGroup_code.value || infraGroupCodesKeys.building,
|
infraGroup_code: infraGroup_code.value || infraGroupCodesKeys.counter,
|
||||||
parent_id: parent_id.value || null,
|
parent_id: parent_id.value || null,
|
||||||
}
|
}
|
||||||
emit('submit', formData, resetForm)
|
emit('submit', formData, resetForm)
|
||||||
|
|||||||
@@ -0,0 +1,207 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
// Components
|
||||||
|
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'
|
||||||
|
import Combobox from '~/components/pub/my-ui/combobox/combobox.vue'
|
||||||
|
|
||||||
|
// Types
|
||||||
|
import type { DivisionPositionFormData } from '~/schemas/division-position.schema'
|
||||||
|
|
||||||
|
// Helpers
|
||||||
|
import type z from 'zod'
|
||||||
|
import { toTypedSchema } from '@vee-validate/zod'
|
||||||
|
import { useForm } from 'vee-validate'
|
||||||
|
import { genBase } from '~/models/_base'
|
||||||
|
import { genDivisionPosition } from '~/models/division-position'
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
schema: z.ZodSchema<any>
|
||||||
|
divisions: any[]
|
||||||
|
employees: any[]
|
||||||
|
values: any
|
||||||
|
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: DivisionPositionFormData, resetForm: () => void]
|
||||||
|
cancel: [resetForm: () => void]
|
||||||
|
}>()
|
||||||
|
|
||||||
|
const { defineField, errors, meta } = useForm({
|
||||||
|
validationSchema: toTypedSchema(props.schema),
|
||||||
|
initialValues: genDivisionPosition() as Partial<DivisionPositionFormData>,
|
||||||
|
})
|
||||||
|
|
||||||
|
const [code, codeAttrs] = defineField('code')
|
||||||
|
const [name, nameAttrs] = defineField('name')
|
||||||
|
const [division, divisionAttrs] = defineField('division_id')
|
||||||
|
const [employee, employeeAttrs] = defineField('employee_id')
|
||||||
|
const [headStatus, headStatusAttrs] = defineField('headStatus')
|
||||||
|
|
||||||
|
// RadioGroup uses string values; expose a string computed that maps to the boolean field
|
||||||
|
const headStatusStr = computed<string>({
|
||||||
|
get() {
|
||||||
|
if (headStatus.value === true) return 'true'
|
||||||
|
if (headStatus.value === false) return 'false'
|
||||||
|
return ''
|
||||||
|
},
|
||||||
|
set(v: string) {
|
||||||
|
if (v === 'true') headStatus.value = true
|
||||||
|
else if (v === 'false') headStatus.value = false
|
||||||
|
else headStatus.value = undefined
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
// Fill fields from props.values if provided
|
||||||
|
if (props.values) {
|
||||||
|
if (props.values.code !== undefined) code.value = props.values.code
|
||||||
|
if (props.values.name !== undefined) name.value = props.values.name
|
||||||
|
if (props.values.division_id !== undefined)
|
||||||
|
division.value = props.values.division_id ? Number(props.values.division_id) : null
|
||||||
|
if (props.values.employee_id !== undefined)
|
||||||
|
employee.value = props.values.employee_id ? Number(props.values.employee_id) : null
|
||||||
|
if (props.values.headStatus !== undefined) headStatus.value = !!props.values.headStatus
|
||||||
|
}
|
||||||
|
|
||||||
|
const resetForm = () => {
|
||||||
|
code.value = ''
|
||||||
|
name.value = ''
|
||||||
|
division.value = null
|
||||||
|
employee.value = null
|
||||||
|
headStatus.value = false
|
||||||
|
}
|
||||||
|
|
||||||
|
// Form submission handler
|
||||||
|
function onSubmitForm() {
|
||||||
|
const formData: DivisionPositionFormData = {
|
||||||
|
...genBase(),
|
||||||
|
name: name.value || '',
|
||||||
|
code: code.value || '',
|
||||||
|
division_id: division.value || null,
|
||||||
|
employee_id: employee.value || null,
|
||||||
|
headStatus: headStatus.value !== undefined ? headStatus.value : undefined,
|
||||||
|
}
|
||||||
|
emit('submit', formData, resetForm)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Form cancel handler
|
||||||
|
function onCancelForm() {
|
||||||
|
emit('cancel', resetForm)
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<form
|
||||||
|
id="form-division-position"
|
||||||
|
@submit.prevent
|
||||||
|
>
|
||||||
|
<Block
|
||||||
|
labelSize="thin"
|
||||||
|
class="!mb-2.5 !pt-0 xl:!mb-3"
|
||||||
|
:colCount="1"
|
||||||
|
>
|
||||||
|
<Cell>
|
||||||
|
<Label height="compact">Kode</Label>
|
||||||
|
<Field :errMessage="errors.code">
|
||||||
|
<Input
|
||||||
|
id="code"
|
||||||
|
v-model="code"
|
||||||
|
v-bind="codeAttrs"
|
||||||
|
:disabled="isLoading || isReadonly"
|
||||||
|
/>
|
||||||
|
</Field>
|
||||||
|
</Cell>
|
||||||
|
<Cell>
|
||||||
|
<Label height="compact">Nama</Label>
|
||||||
|
<Field :errMessage="errors.name">
|
||||||
|
<Input
|
||||||
|
id="name"
|
||||||
|
v-model="name"
|
||||||
|
v-bind="nameAttrs"
|
||||||
|
:disabled="isLoading || isReadonly"
|
||||||
|
/>
|
||||||
|
</Field>
|
||||||
|
</Cell>
|
||||||
|
<Cell>
|
||||||
|
<Label height="compact">Posisi Divisi</Label>
|
||||||
|
<Field :errMessage="errors.division_id">
|
||||||
|
<Combobox
|
||||||
|
id="division"
|
||||||
|
v-model="division"
|
||||||
|
v-bind="divisionAttrs"
|
||||||
|
:items="divisions"
|
||||||
|
:is-disabled="isLoading || isReadonly"
|
||||||
|
placeholder="Pilih Divisi"
|
||||||
|
search-placeholder="Cari Divisi"
|
||||||
|
empty-message="Item tidak ditemukan"
|
||||||
|
/>
|
||||||
|
</Field>
|
||||||
|
</Cell>
|
||||||
|
<Cell>
|
||||||
|
<Label height="compact">Karyawan</Label>
|
||||||
|
<Field :errMessage="errors.employee_id">
|
||||||
|
<Combobox
|
||||||
|
id="employee"
|
||||||
|
v-model="employee"
|
||||||
|
v-bind="employeeAttrs"
|
||||||
|
:items="employees"
|
||||||
|
:is-disabled="isLoading || isReadonly"
|
||||||
|
placeholder="Pilih Karyawan"
|
||||||
|
search-placeholder="Cari Karyawan"
|
||||||
|
empty-message="Item tidak ditemukan"
|
||||||
|
/>
|
||||||
|
</Field>
|
||||||
|
</Cell>
|
||||||
|
<Cell>
|
||||||
|
<Label height="compact">Status Kepala</Label>
|
||||||
|
<Field :errMessage="errors.headStatus">
|
||||||
|
<RadioGroup
|
||||||
|
v-model="headStatusStr"
|
||||||
|
v-bind="headStatusAttrs"
|
||||||
|
class="flex gap-4"
|
||||||
|
>
|
||||||
|
<div class="flex items-center space-x-2">
|
||||||
|
<RadioGroupItem
|
||||||
|
id="head-yes"
|
||||||
|
value="true"
|
||||||
|
/>
|
||||||
|
<Label for="head-yes">Ya</Label>
|
||||||
|
</div>
|
||||||
|
<div class="flex items-center space-x-2">
|
||||||
|
<RadioGroupItem
|
||||||
|
id="head-no"
|
||||||
|
value="false"
|
||||||
|
/>
|
||||||
|
<Label for="head-no">Tidak</Label>
|
||||||
|
</div>
|
||||||
|
</RadioGroup>
|
||||||
|
</Field>
|
||||||
|
</Cell>
|
||||||
|
</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,64 @@
|
|||||||
|
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-ud.vue'))
|
||||||
|
|
||||||
|
export const cols: Col[] = [{}, {}, {}, {}, {}, { width: 50 }]
|
||||||
|
|
||||||
|
export const header: Th[][] = [
|
||||||
|
[
|
||||||
|
{ label: 'Kode' },
|
||||||
|
{ label: 'Nama' },
|
||||||
|
{ label: 'Divisi Induk' },
|
||||||
|
{ label: 'Karyawan' },
|
||||||
|
{ label: 'Status Kepala' },
|
||||||
|
{ label: '' },
|
||||||
|
],
|
||||||
|
]
|
||||||
|
|
||||||
|
export const keys = ['code', 'name', 'division', 'employee', 'head', 'action']
|
||||||
|
|
||||||
|
export const delKeyNames: KeyLabel[] = [
|
||||||
|
{ key: 'code', label: 'Kode' },
|
||||||
|
{ key: 'name', label: 'Nama' },
|
||||||
|
]
|
||||||
|
|
||||||
|
export const funcParsed: RecStrFuncUnknown = {
|
||||||
|
division: (rec: unknown): unknown => {
|
||||||
|
const recX = rec as SmallDetailDto
|
||||||
|
return recX.division?.name || '-'
|
||||||
|
},
|
||||||
|
employee: (rec: unknown): unknown => {
|
||||||
|
const recX = rec as SmallDetailDto
|
||||||
|
return recX.employee?.name || '-'
|
||||||
|
},
|
||||||
|
head: (rec: unknown): unknown => {
|
||||||
|
const recX = rec as SmallDetailDto
|
||||||
|
return recX.headStatus ? 'Ya' : 'Tidak'
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
export const funcComponent: RecStrFuncComponent = {
|
||||||
|
action(rec, idx) {
|
||||||
|
const res: RecComponent = {
|
||||||
|
idx,
|
||||||
|
rec: rec as object,
|
||||||
|
component: action,
|
||||||
|
props: {
|
||||||
|
size: 'sm',
|
||||||
|
},
|
||||||
|
}
|
||||||
|
return res
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
export const funcHtml: RecStrFuncUnknown = {}
|
||||||
@@ -0,0 +1,41 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
// Components
|
||||||
|
import PaginationView from '~/components/pub/my-ui/pagination/pagination-view.vue'
|
||||||
|
|
||||||
|
// Types
|
||||||
|
import type { PaginationMeta } from '~/components/pub/my-ui/pagination/pagination.type'
|
||||||
|
|
||||||
|
// Configs
|
||||||
|
import { cols, funcComponent, funcHtml, funcParsed, header, keys } from './list-cfg'
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
data: any[]
|
||||||
|
paginationMeta: PaginationMeta
|
||||||
|
}
|
||||||
|
|
||||||
|
defineProps<Props>()
|
||||||
|
|
||||||
|
const emit = defineEmits<{
|
||||||
|
pageChange: [page: number]
|
||||||
|
}>()
|
||||||
|
|
||||||
|
function handlePageChange(page: number) {
|
||||||
|
emit('pageChange', page)
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="space-y-4">
|
||||||
|
<PubMyUiDataTable
|
||||||
|
:rows="data"
|
||||||
|
:cols="cols"
|
||||||
|
:header="header"
|
||||||
|
:keys="keys"
|
||||||
|
:func-parsed="funcParsed"
|
||||||
|
:func-html="funcHtml"
|
||||||
|
:func-component="funcComponent"
|
||||||
|
:skeleton-size="paginationMeta?.pageSize"
|
||||||
|
/>
|
||||||
|
<PaginationView :pagination-meta="paginationMeta" @page-change="handlePageChange" />
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
@@ -7,12 +7,13 @@ import Label from '~/components/pub/my-ui/doc-entry/label.vue'
|
|||||||
import TreeSelect from '~/components/pub/my-ui/select-tree/tree-select.vue'
|
import TreeSelect from '~/components/pub/my-ui/select-tree/tree-select.vue'
|
||||||
|
|
||||||
// Types
|
// Types
|
||||||
import type { DivisionFormData } from '~/schemas/division.schema.ts'
|
import type { DivisionFormData } from '~/schemas/division.schema'
|
||||||
|
|
||||||
// Helpers
|
// Helpers
|
||||||
import type z from 'zod'
|
import type z from 'zod'
|
||||||
import { toTypedSchema } from '@vee-validate/zod'
|
import { toTypedSchema } from '@vee-validate/zod'
|
||||||
import { useForm } from 'vee-validate'
|
import { useForm } from 'vee-validate'
|
||||||
|
import { genBase } from '~/models/_base'
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
schema: z.ZodSchema<any>
|
schema: z.ZodSchema<any>
|
||||||
@@ -36,37 +37,33 @@ const { defineField, errors, meta } = useForm({
|
|||||||
code: '',
|
code: '',
|
||||||
name: '',
|
name: '',
|
||||||
parent_id: null,
|
parent_id: null,
|
||||||
division_id: null,
|
|
||||||
} as Partial<DivisionFormData>,
|
} as Partial<DivisionFormData>,
|
||||||
})
|
})
|
||||||
|
|
||||||
const [code, codeAttrs] = defineField('code')
|
const [code, codeAttrs] = defineField('code')
|
||||||
const [name, nameAttrs] = defineField('name')
|
const [name, nameAttrs] = defineField('name')
|
||||||
const [parent, parentAttrs] = defineField('parent_id')
|
const [parent, parentAttrs] = defineField('parent_id')
|
||||||
const [division] = defineField('division_id')
|
|
||||||
|
|
||||||
// Fill fields from props.values if provided
|
// Fill fields from props.values if provided
|
||||||
if (props.values) {
|
if (props.values) {
|
||||||
if (props.values.code !== undefined) code.value = props.values.code
|
if (props.values.code !== undefined) code.value = props.values.code
|
||||||
if (props.values.name !== undefined) name.value = props.values.name
|
if (props.values.name !== undefined) name.value = props.values.name
|
||||||
if (props.values.parent_id !== undefined) parent.value = String(props.values.parent_id)
|
if (props.values.parent_id !== undefined) parent.value = String(props.values.parent_id)
|
||||||
if (props.values.division_id !== undefined) division.value = String(props.values.division_id)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const resetForm = () => {
|
const resetForm = () => {
|
||||||
code.value = ''
|
code.value = ''
|
||||||
name.value = ''
|
name.value = ''
|
||||||
parent.value = null
|
parent.value = null
|
||||||
division.value = null
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Form submission handler
|
// Form submission handler
|
||||||
function onSubmitForm() {
|
function onSubmitForm() {
|
||||||
const formData: DivisionFormData = {
|
const formData: DivisionFormData = {
|
||||||
|
...genBase(),
|
||||||
name: name.value || '',
|
name: name.value || '',
|
||||||
code: code.value || '',
|
code: code.value || '',
|
||||||
parent_id: parent.value || null,
|
parent_id: parent.value || null,
|
||||||
division_id: division.value || null,
|
|
||||||
}
|
}
|
||||||
emit('submit', formData, resetForm)
|
emit('submit', formData, resetForm)
|
||||||
}
|
}
|
||||||
@@ -78,25 +75,42 @@ function onCancelForm() {
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<form id="form-division" @submit.prevent>
|
<form
|
||||||
<Block labelSize="thin" class="!mb-2.5 !pt-0 xl:!mb-3" :colCount="1">
|
id="form-division"
|
||||||
|
@submit.prevent
|
||||||
|
>
|
||||||
|
<Block
|
||||||
|
labelSize="thin"
|
||||||
|
class="!mb-2.5 !pt-0 xl:!mb-3"
|
||||||
|
:colCount="1"
|
||||||
|
>
|
||||||
<Cell>
|
<Cell>
|
||||||
<Label height="compact">Kode</Label>
|
<Label height="compact">Kode</Label>
|
||||||
<Field :errMessage="errors.code">
|
<Field :errMessage="errors.code">
|
||||||
<Input id="code" v-model="code" v-bind="codeAttrs" :disabled="isLoading || isReadonly" />
|
<Input
|
||||||
|
id="code"
|
||||||
|
v-model="code"
|
||||||
|
v-bind="codeAttrs"
|
||||||
|
:disabled="isLoading || isReadonly"
|
||||||
|
/>
|
||||||
</Field>
|
</Field>
|
||||||
</Cell>
|
</Cell>
|
||||||
<Cell>
|
<Cell>
|
||||||
<Label height="compact">Nama</Label>
|
<Label height="compact">Nama</Label>
|
||||||
<Field :errMessage="errors.name">
|
<Field :errMessage="errors.name">
|
||||||
<Input id="name" v-model="name" v-bind="nameAttrs" :disabled="isLoading || isReadonly" />
|
<Input
|
||||||
|
id="name"
|
||||||
|
v-model="name"
|
||||||
|
v-bind="nameAttrs"
|
||||||
|
:disabled="isLoading || isReadonly"
|
||||||
|
/>
|
||||||
</Field>
|
</Field>
|
||||||
</Cell>
|
</Cell>
|
||||||
<Cell>
|
<Cell>
|
||||||
<Label height="compact">Divisi Induk</Label>
|
<Label height="compact">Divisi Induk</Label>
|
||||||
<Field :errMessage="errors.division">
|
<Field :errMessage="errors.parent_id">
|
||||||
<TreeSelect
|
<TreeSelect
|
||||||
id="division"
|
id="parent"
|
||||||
v-model="parent"
|
v-model="parent"
|
||||||
v-bind="parentAttrs"
|
v-bind="parentAttrs"
|
||||||
:data="divisions"
|
:data="divisions"
|
||||||
@@ -110,7 +124,14 @@ function onCancelForm() {
|
|||||||
</Cell>
|
</Cell>
|
||||||
</Block>
|
</Block>
|
||||||
<div class="my-2 flex justify-end gap-2 py-2">
|
<div class="my-2 flex justify-end gap-2 py-2">
|
||||||
<Button type="button" variant="secondary" class="w-[120px]" @click="onCancelForm"> Kembali </Button>
|
<Button
|
||||||
|
type="button"
|
||||||
|
variant="secondary"
|
||||||
|
class="w-[120px]"
|
||||||
|
@click="onCancelForm"
|
||||||
|
>
|
||||||
|
Kembali
|
||||||
|
</Button>
|
||||||
<Button
|
<Button
|
||||||
v-if="!isReadonly"
|
v-if="!isReadonly"
|
||||||
type="button"
|
type="button"
|
||||||
|
|||||||
@@ -5,9 +5,9 @@ import Block from '~/components/pub/my-ui/doc-entry/block.vue'
|
|||||||
import Cell from '~/components/pub/my-ui/doc-entry/cell.vue'
|
import Cell from '~/components/pub/my-ui/doc-entry/cell.vue'
|
||||||
import Field from '~/components/pub/my-ui/doc-entry/field.vue'
|
import Field from '~/components/pub/my-ui/doc-entry/field.vue'
|
||||||
import Label from '~/components/pub/my-ui/doc-entry/label.vue'
|
import Label from '~/components/pub/my-ui/doc-entry/label.vue'
|
||||||
import Combobox from '~/components/pub/my-ui/form/combobox.vue'
|
import Combobox from '~/components/pub/my-ui/combobox/combobox.vue'
|
||||||
import { Form } from '~/components/pub/ui/form'
|
import { Form } from '~/components/pub/ui/form'
|
||||||
import DatepickerSingle from '~/components/pub/my-ui/form/datepicker-single.vue'
|
import DatepickerSingle from '~/components/pub/my-ui/datepicker/datepicker-single.vue'
|
||||||
|
|
||||||
import { educationCodes, genderCodes, occupationCodes, religionCodes, relationshipCodes } from '~/lib/constants'
|
import { educationCodes, genderCodes, occupationCodes, religionCodes, relationshipCodes } from '~/lib/constants'
|
||||||
import { mapToComboboxOptList } from '~/lib/utils'
|
import { mapToComboboxOptList } from '~/lib/utils'
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ defineProps<{
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="w-full rounded-md border bg-white p-4 shadow-sm">
|
<div class="w-full rounded-md border bg-white dark:bg-neutral-950 p-4 shadow-sm">
|
||||||
<!-- Data Pasien -->
|
<!-- Data Pasien -->
|
||||||
<h2 class="mb-2 md:text-base 2xl:text-lg font-semibold">{{ 'data.patient.person.name' }} - {{ 'data.patient.number' }}</h2>
|
<h2 class="mb-2 md:text-base 2xl:text-lg font-semibold">{{ 'data.patient.person.name' }} - {{ 'data.patient.number' }}</h2>
|
||||||
|
|
||||||
|
|||||||
@@ -6,12 +6,13 @@ import Field from '~/components/pub/my-ui/doc-entry/field.vue'
|
|||||||
import Label from '~/components/pub/my-ui/doc-entry/label.vue'
|
import Label from '~/components/pub/my-ui/doc-entry/label.vue'
|
||||||
|
|
||||||
// Types
|
// Types
|
||||||
import type { MaterialFormData } from '~/schemas/material.schema.ts'
|
import type { MaterialFormData } from '~/schemas/material.schema'
|
||||||
|
|
||||||
// Helpers
|
// Helpers
|
||||||
import type z from 'zod'
|
import type z from 'zod'
|
||||||
import { useForm } from 'vee-validate'
|
import { useForm } from 'vee-validate'
|
||||||
import { toTypedSchema } from '@vee-validate/zod'
|
import { toTypedSchema } from '@vee-validate/zod'
|
||||||
|
import { genBase } from '~/models/_base'
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
schema: z.ZodSchema<any>
|
schema: z.ZodSchema<any>
|
||||||
@@ -61,6 +62,7 @@ const resetForm = () => {
|
|||||||
|
|
||||||
function onSubmitForm() {
|
function onSubmitForm() {
|
||||||
const formData: MaterialFormData = {
|
const formData: MaterialFormData = {
|
||||||
|
...genBase(),
|
||||||
name: name.value || '',
|
name: name.value || '',
|
||||||
code: code.value || '',
|
code: code.value || '',
|
||||||
uom_code: uom.value || '',
|
uom_code: uom.value || '',
|
||||||
@@ -75,18 +77,35 @@ function onCancelForm() {
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<form id="form-equipment" @submit.prevent>
|
<form
|
||||||
<Block labelSize="thin" class="!mb-2.5 !pt-0 xl:!mb-3" :colCount="1">
|
id="form-equipment"
|
||||||
|
@submit.prevent
|
||||||
|
>
|
||||||
|
<Block
|
||||||
|
labelSize="thin"
|
||||||
|
class="!mb-2.5 !pt-0 xl:!mb-3"
|
||||||
|
:colCount="1"
|
||||||
|
>
|
||||||
<Cell>
|
<Cell>
|
||||||
<Label height="">Kode</Label>
|
<Label height="">Kode</Label>
|
||||||
<Field :errMessage="errors.code">
|
<Field :errMessage="errors.code">
|
||||||
<Input id="code" v-model="code" v-bind="codeAttrs" :disabled="isLoading || isReadonly" />
|
<Input
|
||||||
|
id="code"
|
||||||
|
v-model="code"
|
||||||
|
v-bind="codeAttrs"
|
||||||
|
:disabled="isLoading || isReadonly"
|
||||||
|
/>
|
||||||
</Field>
|
</Field>
|
||||||
</Cell>
|
</Cell>
|
||||||
<Cell>
|
<Cell>
|
||||||
<Label height="compact">Nama</Label>
|
<Label height="compact">Nama</Label>
|
||||||
<Field :errMessage="errors.name">
|
<Field :errMessage="errors.name">
|
||||||
<Input id="name" v-model="name" v-bind="nameAttrs" :disabled="isLoading || isReadonly" />
|
<Input
|
||||||
|
id="name"
|
||||||
|
v-model="name"
|
||||||
|
v-bind="nameAttrs"
|
||||||
|
:disabled="isLoading || isReadonly"
|
||||||
|
/>
|
||||||
</Field>
|
</Field>
|
||||||
</Cell>
|
</Cell>
|
||||||
<Cell>
|
<Cell>
|
||||||
@@ -106,12 +125,25 @@ function onCancelForm() {
|
|||||||
<Cell>
|
<Cell>
|
||||||
<Label height="compact">Stok</Label>
|
<Label height="compact">Stok</Label>
|
||||||
<Field :errMessage="errors.stock">
|
<Field :errMessage="errors.stock">
|
||||||
<Input id="stock" v-model="stock" type="number" v-bind="stockAttrs" :disabled="isLoading || isReadonly" />
|
<Input
|
||||||
|
id="stock"
|
||||||
|
v-model="stock"
|
||||||
|
type="number"
|
||||||
|
v-bind="stockAttrs"
|
||||||
|
:disabled="isLoading || isReadonly"
|
||||||
|
/>
|
||||||
</Field>
|
</Field>
|
||||||
</Cell>
|
</Cell>
|
||||||
</Block>
|
</Block>
|
||||||
<div class="my-2 flex justify-end gap-2 py-2">
|
<div class="my-2 flex justify-end gap-2 py-2">
|
||||||
<Button type="button" variant="secondary" class="w-[120px]" @click="onCancelForm"> Kembali </Button>
|
<Button
|
||||||
|
type="button"
|
||||||
|
variant="secondary"
|
||||||
|
class="w-[120px]"
|
||||||
|
@click="onCancelForm"
|
||||||
|
>
|
||||||
|
Kembali
|
||||||
|
</Button>
|
||||||
<Button
|
<Button
|
||||||
v-if="!isReadonly"
|
v-if="!isReadonly"
|
||||||
type="button"
|
type="button"
|
||||||
|
|||||||
@@ -5,10 +5,10 @@ import Cell from '~/components/pub/my-ui/doc-entry/cell.vue'
|
|||||||
import Field from '~/components/pub/my-ui/doc-entry/field.vue'
|
import Field from '~/components/pub/my-ui/doc-entry/field.vue'
|
||||||
import Label from '~/components/pub/my-ui/doc-entry/label.vue'
|
import Label from '~/components/pub/my-ui/doc-entry/label.vue'
|
||||||
import Button from '~/components/pub/ui/button/Button.vue'
|
import Button from '~/components/pub/ui/button/Button.vue'
|
||||||
import Combobox from '~/components/pub/my-ui/form/combobox.vue'
|
import Combobox from '~/components/pub/my-ui/combobox/combobox.vue'
|
||||||
|
|
||||||
// Constants
|
// Constants
|
||||||
import { infraGroupCodesKeys } from "~/lib/constants"
|
import { infraGroupCodesKeys } from '~/lib/constants'
|
||||||
|
|
||||||
// Types
|
// Types
|
||||||
import type { InfraFormData } from '~/schemas/infra.schema'
|
import type { InfraFormData } from '~/schemas/infra.schema'
|
||||||
@@ -53,7 +53,8 @@ if (props.values) {
|
|||||||
if (props.values.code !== undefined) code.value = props.values.code
|
if (props.values.code !== undefined) code.value = props.values.code
|
||||||
if (props.values.name !== undefined) name.value = props.values.name
|
if (props.values.name !== undefined) name.value = props.values.name
|
||||||
if (props.values.infraGroup_code !== undefined) infraGroup_code.value = props.values.infraGroup_code
|
if (props.values.infraGroup_code !== undefined) infraGroup_code.value = props.values.infraGroup_code
|
||||||
if (props.values.parent_id !== undefined) parent_id.value = String(props.values.parent_id)
|
if (props.values.parent_id !== undefined)
|
||||||
|
parent_id.value = props.values.parent_id ? Number(props.values.parent_id) : null
|
||||||
}
|
}
|
||||||
|
|
||||||
const resetForm = () => {
|
const resetForm = () => {
|
||||||
@@ -79,18 +80,35 @@ function onCancelForm() {
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<form id="form-floor" @submit.prevent>
|
<form
|
||||||
<Block labelSize="thin" class="!mb-2.5 !pt-0 xl:!mb-3" :colCount="1">
|
id="form-floor"
|
||||||
|
@submit.prevent
|
||||||
|
>
|
||||||
|
<Block
|
||||||
|
labelSize="thin"
|
||||||
|
class="!mb-2.5 !pt-0 xl:!mb-3"
|
||||||
|
:colCount="1"
|
||||||
|
>
|
||||||
<Cell>
|
<Cell>
|
||||||
<Label height="compact">Kode</Label>
|
<Label height="compact">Kode</Label>
|
||||||
<Field :errMessage="errors.code">
|
<Field :errMessage="errors.code">
|
||||||
<Input id="code" v-model="code" v-bind="codeAttrs" :disabled="isLoading || isReadonly" />
|
<Input
|
||||||
|
id="code"
|
||||||
|
v-model="code"
|
||||||
|
v-bind="codeAttrs"
|
||||||
|
:disabled="isLoading || isReadonly"
|
||||||
|
/>
|
||||||
</Field>
|
</Field>
|
||||||
</Cell>
|
</Cell>
|
||||||
<Cell>
|
<Cell>
|
||||||
<Label height="compact">Nama</Label>
|
<Label height="compact">Nama</Label>
|
||||||
<Field :errMessage="errors.name">
|
<Field :errMessage="errors.name">
|
||||||
<Input id="name" v-model="name" v-bind="nameAttrs" :disabled="isLoading || isReadonly" />
|
<Input
|
||||||
|
id="name"
|
||||||
|
v-model="name"
|
||||||
|
v-bind="nameAttrs"
|
||||||
|
:disabled="isLoading || isReadonly"
|
||||||
|
/>
|
||||||
</Field>
|
</Field>
|
||||||
</Cell>
|
</Cell>
|
||||||
<Cell>
|
<Cell>
|
||||||
@@ -101,7 +119,7 @@ function onCancelForm() {
|
|||||||
v-model="parent_id"
|
v-model="parent_id"
|
||||||
v-bind="parentIdAttrs"
|
v-bind="parentIdAttrs"
|
||||||
:items="parents"
|
:items="parents"
|
||||||
:disabled="isLoading || isReadonly"
|
:is-disabled="isLoading || isReadonly"
|
||||||
placeholder="Pilih Gedung"
|
placeholder="Pilih Gedung"
|
||||||
search-placeholder="Cari Gedung"
|
search-placeholder="Cari Gedung"
|
||||||
empty-message="Item tidak ditemukan"
|
empty-message="Item tidak ditemukan"
|
||||||
@@ -110,7 +128,14 @@ function onCancelForm() {
|
|||||||
</Cell>
|
</Cell>
|
||||||
</Block>
|
</Block>
|
||||||
<div class="my-2 flex justify-end gap-2 py-2">
|
<div class="my-2 flex justify-end gap-2 py-2">
|
||||||
<Button type="button" variant="secondary" class="w-[120px]" @click="onCancelForm"> Kembali </Button>
|
<Button
|
||||||
|
type="button"
|
||||||
|
variant="secondary"
|
||||||
|
class="w-[120px]"
|
||||||
|
@click="onCancelForm"
|
||||||
|
>
|
||||||
|
Kembali
|
||||||
|
</Button>
|
||||||
<Button
|
<Button
|
||||||
v-if="!isReadonly"
|
v-if="!isReadonly"
|
||||||
type="button"
|
type="button"
|
||||||
|
|||||||
@@ -4,10 +4,10 @@ import Block from '~/components/pub/my-ui/doc-entry/block.vue'
|
|||||||
import Cell from '~/components/pub/my-ui/doc-entry/cell.vue'
|
import Cell from '~/components/pub/my-ui/doc-entry/cell.vue'
|
||||||
import Field from '~/components/pub/my-ui/doc-entry/field.vue'
|
import Field from '~/components/pub/my-ui/doc-entry/field.vue'
|
||||||
import Label from '~/components/pub/my-ui/doc-entry/label.vue'
|
import Label from '~/components/pub/my-ui/doc-entry/label.vue'
|
||||||
import Combobox from '~/components/pub/my-ui/form/combobox.vue'
|
import Combobox from '~/components/pub/my-ui/combobox/combobox.vue'
|
||||||
|
|
||||||
// Types
|
// Types
|
||||||
import type { InstallationFormData } from '~/schemas/installation.schema.ts'
|
import type { InstallationFormData } from '~/schemas/installation.schema'
|
||||||
|
|
||||||
// Helpers
|
// Helpers
|
||||||
import type z from 'zod'
|
import type z from 'zod'
|
||||||
@@ -73,18 +73,35 @@ function onCancelForm() {
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<form id="form-unit" @submit.prevent>
|
<form
|
||||||
<Block labelSize="thin" class="!mb-2.5 !pt-0 xl:!mb-3" :colCount="1">
|
id="form-unit"
|
||||||
|
@submit.prevent
|
||||||
|
>
|
||||||
|
<Block
|
||||||
|
labelSize="thin"
|
||||||
|
class="!mb-2.5 !pt-0 xl:!mb-3"
|
||||||
|
:colCount="1"
|
||||||
|
>
|
||||||
<Cell>
|
<Cell>
|
||||||
<Label height="compact">Kode</Label>
|
<Label height="compact">Kode</Label>
|
||||||
<Field :errMessage="errors.code">
|
<Field :errMessage="errors.code">
|
||||||
<Input id="code" v-model="code" v-bind="codeAttrs" :disabled="isLoading || isReadonly" />
|
<Input
|
||||||
|
id="code"
|
||||||
|
v-model="code"
|
||||||
|
v-bind="codeAttrs"
|
||||||
|
:disabled="isLoading || isReadonly"
|
||||||
|
/>
|
||||||
</Field>
|
</Field>
|
||||||
</Cell>
|
</Cell>
|
||||||
<Cell>
|
<Cell>
|
||||||
<Label height="compact">Nama</Label>
|
<Label height="compact">Nama</Label>
|
||||||
<Field :errMessage="errors.name">
|
<Field :errMessage="errors.name">
|
||||||
<Input id="name" v-model="name" v-bind="nameAttrs" :disabled="isLoading || isReadonly" />
|
<Input
|
||||||
|
id="name"
|
||||||
|
v-model="name"
|
||||||
|
v-bind="nameAttrs"
|
||||||
|
:disabled="isLoading || isReadonly"
|
||||||
|
/>
|
||||||
</Field>
|
</Field>
|
||||||
</Cell>
|
</Cell>
|
||||||
<Cell>
|
<Cell>
|
||||||
@@ -104,7 +121,14 @@ function onCancelForm() {
|
|||||||
</Cell>
|
</Cell>
|
||||||
</Block>
|
</Block>
|
||||||
<div class="my-2 flex justify-end gap-2 py-2">
|
<div class="my-2 flex justify-end gap-2 py-2">
|
||||||
<Button type="button" variant="secondary" class="w-[120px]" @click="onCancelForm"> Kembali </Button>
|
<Button
|
||||||
|
type="button"
|
||||||
|
variant="secondary"
|
||||||
|
class="w-[120px]"
|
||||||
|
@click="onCancelForm"
|
||||||
|
>
|
||||||
|
Kembali
|
||||||
|
</Button>
|
||||||
<Button
|
<Button
|
||||||
v-if="!isReadonly"
|
v-if="!isReadonly"
|
||||||
type="button"
|
type="button"
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
// Components
|
// Components
|
||||||
import Block from '~/components/pub/my-ui/doc-entry/block.vue'
|
import Block from '~/components/pub/my-ui/doc-entry/block.vue'
|
||||||
@@ -8,7 +7,7 @@ import Label from '~/components/pub/my-ui/doc-entry/label.vue'
|
|||||||
import Button from '~/components/pub/ui/button/Button.vue'
|
import Button from '~/components/pub/ui/button/Button.vue'
|
||||||
|
|
||||||
// Types
|
// Types
|
||||||
import type { BaseFormData } from '~/schemas/base.schema.ts'
|
import type { BaseFormData } from '~/schemas/base.schema'
|
||||||
|
|
||||||
// Helpers
|
// Helpers
|
||||||
import type z from 'zod'
|
import type z from 'zod'
|
||||||
@@ -65,23 +64,47 @@ function onCancelForm() {
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<form id="form-medicine-group" @submit.prevent>
|
<form
|
||||||
<Block labelSize="thin" class="!mb-2.5 !pt-0 xl:!mb-3" :colCount="1">
|
id="form-medicine-group"
|
||||||
|
@submit.prevent
|
||||||
|
>
|
||||||
|
<Block
|
||||||
|
labelSize="thin"
|
||||||
|
class="!mb-2.5 !pt-0 xl:!mb-3"
|
||||||
|
:colCount="1"
|
||||||
|
>
|
||||||
<Cell>
|
<Cell>
|
||||||
<Label height="">Kode</Label>
|
<Label height="">Kode</Label>
|
||||||
<Field :errMessage="errors.code">
|
<Field :errMessage="errors.code">
|
||||||
<Input id="code" v-model="code" v-bind="codeAttrs" :disabled="isLoading || isReadonly" />
|
<Input
|
||||||
|
id="code"
|
||||||
|
v-model="code"
|
||||||
|
v-bind="codeAttrs"
|
||||||
|
:disabled="isLoading || isReadonly"
|
||||||
|
/>
|
||||||
</Field>
|
</Field>
|
||||||
</Cell>
|
</Cell>
|
||||||
<Cell>
|
<Cell>
|
||||||
<Label height="compact">Nama</Label>
|
<Label height="compact">Nama</Label>
|
||||||
<Field :errMessage="errors.name">
|
<Field :errMessage="errors.name">
|
||||||
<Input id="name" v-model="name" v-bind="nameAttrs" :disabled="isLoading || isReadonly" />
|
<Input
|
||||||
|
id="name"
|
||||||
|
v-model="name"
|
||||||
|
v-bind="nameAttrs"
|
||||||
|
:disabled="isLoading || isReadonly"
|
||||||
|
/>
|
||||||
</Field>
|
</Field>
|
||||||
</Cell>
|
</Cell>
|
||||||
</Block>
|
</Block>
|
||||||
<div class="my-2 flex justify-end gap-2 py-2">
|
<div class="my-2 flex justify-end gap-2 py-2">
|
||||||
<Button type="button" variant="secondary" class="w-[120px]" @click="onCancelForm"> Kembali </Button>
|
<Button
|
||||||
|
type="button"
|
||||||
|
variant="secondary"
|
||||||
|
class="w-[120px]"
|
||||||
|
@click="onCancelForm"
|
||||||
|
>
|
||||||
|
Kembali
|
||||||
|
</Button>
|
||||||
<Button
|
<Button
|
||||||
v-if="!isReadonly"
|
v-if="!isReadonly"
|
||||||
type="button"
|
type="button"
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
// Components
|
// Components
|
||||||
import Block from '~/components/pub/my-ui/doc-entry/block.vue'
|
import Block from '~/components/pub/my-ui/doc-entry/block.vue'
|
||||||
@@ -8,7 +7,7 @@ import Label from '~/components/pub/my-ui/doc-entry/label.vue'
|
|||||||
import Button from '~/components/pub/ui/button/Button.vue'
|
import Button from '~/components/pub/ui/button/Button.vue'
|
||||||
|
|
||||||
// Types
|
// Types
|
||||||
import type { BaseFormData } from '~/schemas/base.schema.ts'
|
import type { BaseFormData } from '~/schemas/base.schema'
|
||||||
|
|
||||||
// Helpers
|
// Helpers
|
||||||
import type z from 'zod'
|
import type z from 'zod'
|
||||||
@@ -65,23 +64,47 @@ function onCancelForm() {
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<form id="form-medicine-method" @submit.prevent>
|
<form
|
||||||
<Block labelSize="thin" class="!mb-2.5 !pt-0 xl:!mb-3" :colCount="1">
|
id="form-medicine-method"
|
||||||
|
@submit.prevent
|
||||||
|
>
|
||||||
|
<Block
|
||||||
|
labelSize="thin"
|
||||||
|
class="!mb-2.5 !pt-0 xl:!mb-3"
|
||||||
|
:colCount="1"
|
||||||
|
>
|
||||||
<Cell>
|
<Cell>
|
||||||
<Label height="">Kode</Label>
|
<Label height="">Kode</Label>
|
||||||
<Field :errMessage="errors.code">
|
<Field :errMessage="errors.code">
|
||||||
<Input id="code" v-model="code" v-bind="codeAttrs" :disabled="isLoading || isReadonly" />
|
<Input
|
||||||
|
id="code"
|
||||||
|
v-model="code"
|
||||||
|
v-bind="codeAttrs"
|
||||||
|
:disabled="isLoading || isReadonly"
|
||||||
|
/>
|
||||||
</Field>
|
</Field>
|
||||||
</Cell>
|
</Cell>
|
||||||
<Cell>
|
<Cell>
|
||||||
<Label height="compact">Nama</Label>
|
<Label height="compact">Nama</Label>
|
||||||
<Field :errMessage="errors.name">
|
<Field :errMessage="errors.name">
|
||||||
<Input id="name" v-model="name" v-bind="nameAttrs" :disabled="isLoading || isReadonly" />
|
<Input
|
||||||
|
id="name"
|
||||||
|
v-model="name"
|
||||||
|
v-bind="nameAttrs"
|
||||||
|
:disabled="isLoading || isReadonly"
|
||||||
|
/>
|
||||||
</Field>
|
</Field>
|
||||||
</Cell>
|
</Cell>
|
||||||
</Block>
|
</Block>
|
||||||
<div class="my-2 flex justify-end gap-2 py-2">
|
<div class="my-2 flex justify-end gap-2 py-2">
|
||||||
<Button type="button" variant="secondary" class="w-[120px]" @click="onCancelForm"> Kembali </Button>
|
<Button
|
||||||
|
type="button"
|
||||||
|
variant="secondary"
|
||||||
|
class="w-[120px]"
|
||||||
|
@click="onCancelForm"
|
||||||
|
>
|
||||||
|
Kembali
|
||||||
|
</Button>
|
||||||
<Button
|
<Button
|
||||||
v-if="!isReadonly"
|
v-if="!isReadonly"
|
||||||
type="button"
|
type="button"
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import type { FormErrors } from '~/types/error'
|
import type { FormErrors } from '~/types/error'
|
||||||
import Combobox from '~/components/pub/my-ui/form/combobox.vue'
|
import Combobox from '~/components/pub/my-ui/combobox/combobox.vue'
|
||||||
import FieldGroup from '~/components/pub/my-ui/form/field-group.vue'
|
import FieldGroup from '~/components/pub/my-ui/form/field-group.vue'
|
||||||
import Field from '~/components/pub/my-ui/form/field.vue'
|
import Field from '~/components/pub/my-ui/form/field.vue'
|
||||||
import Label from '~/components/pub/my-ui/form/label.vue'
|
import Label from '~/components/pub/my-ui/form/label.vue'
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import type { FormErrors } from '~/types/error'
|
import type { FormErrors } from '~/types/error'
|
||||||
import Combobox from '~/components/pub/my-ui/form/combobox.vue'
|
import Combobox from '~/components/pub/my-ui/combobox/combobox.vue'
|
||||||
import FieldGroup from '~/components/pub/my-ui/form/field-group.vue'
|
import FieldGroup from '~/components/pub/my-ui/form/field-group.vue'
|
||||||
import Field from '~/components/pub/my-ui/form/field.vue'
|
import Field from '~/components/pub/my-ui/form/field.vue'
|
||||||
import Label from '~/components/pub/my-ui/form/label.vue'
|
import Label from '~/components/pub/my-ui/form/label.vue'
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import type { FormErrors } from '~/types/error'
|
import type { FormErrors } from '~/types/error'
|
||||||
import Combobox from '~/components/pub/my-ui/form/combobox.vue'
|
import Combobox from '~/components/pub/my-ui/combobox/combobox.vue'
|
||||||
import FieldGroup from '~/components/pub/my-ui/form/field-group.vue'
|
import FieldGroup from '~/components/pub/my-ui/form/field-group.vue'
|
||||||
import Field from '~/components/pub/my-ui/form/field.vue'
|
import Field from '~/components/pub/my-ui/form/field.vue'
|
||||||
import Label from '~/components/pub/my-ui/form/label.vue'
|
import Label from '~/components/pub/my-ui/form/label.vue'
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import type { FormErrors } from '~/types/error'
|
import type { FormErrors } from '~/types/error'
|
||||||
import Combobox from '~/components/pub/my-ui/form/combobox.vue'
|
import Combobox from '~/components/pub/my-ui/combobox/combobox.vue'
|
||||||
import FieldGroup from '~/components/pub/my-ui/form/field-group.vue'
|
import FieldGroup from '~/components/pub/my-ui/form/field-group.vue'
|
||||||
import Field from '~/components/pub/my-ui/form/field.vue'
|
import Field from '~/components/pub/my-ui/form/field.vue'
|
||||||
import Label from '~/components/pub/my-ui/form/label.vue'
|
import Label from '~/components/pub/my-ui/form/label.vue'
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import type { FormErrors } from '~/types/error'
|
import type { FormErrors } from '~/types/error'
|
||||||
import Combobox from '~/components/pub/my-ui/form/combobox.vue'
|
import Combobox from '~/components/pub/my-ui/combobox/combobox.vue'
|
||||||
import FieldGroup from '~/components/pub/my-ui/form/field-group.vue'
|
import FieldGroup from '~/components/pub/my-ui/form/field-group.vue'
|
||||||
import Field from '~/components/pub/my-ui/form/field.vue'
|
import Field from '~/components/pub/my-ui/form/field.vue'
|
||||||
import Label from '~/components/pub/my-ui/form/label.vue'
|
import Label from '~/components/pub/my-ui/form/label.vue'
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import type { FormErrors } from '~/types/error'
|
import type { FormErrors } from '~/types/error'
|
||||||
import Combobox from '~/components/pub/my-ui/form/combobox.vue'
|
import Combobox from '~/components/pub/my-ui/combobox/combobox.vue'
|
||||||
import FieldGroup from '~/components/pub/my-ui/form/field-group.vue'
|
import FieldGroup from '~/components/pub/my-ui/form/field-group.vue'
|
||||||
import Field from '~/components/pub/my-ui/form/field.vue'
|
import Field from '~/components/pub/my-ui/form/field.vue'
|
||||||
import Label from '~/components/pub/my-ui/form/label.vue'
|
import Label from '~/components/pub/my-ui/form/label.vue'
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import type { FormErrors } from '~/types/error'
|
import type { FormErrors } from '~/types/error'
|
||||||
import Combobox from '~/components/pub/my-ui/form/combobox.vue'
|
import Combobox from '~/components/pub/my-ui/combobox/combobox.vue'
|
||||||
import FieldGroup from '~/components/pub/my-ui/form/field-group.vue'
|
import FieldGroup from '~/components/pub/my-ui/form/field-group.vue'
|
||||||
import Field from '~/components/pub/my-ui/form/field.vue'
|
import Field from '~/components/pub/my-ui/form/field.vue'
|
||||||
import Label from '~/components/pub/my-ui/form/label.vue'
|
import Label from '~/components/pub/my-ui/form/label.vue'
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import type { FormErrors } from '~/types/error'
|
|||||||
import { Form } from '~/components/pub/ui/form'
|
import { Form } from '~/components/pub/ui/form'
|
||||||
import { toTypedSchema } from '@vee-validate/zod'
|
import { toTypedSchema } from '@vee-validate/zod'
|
||||||
import Block from '~/components/pub/my-ui/form/block.vue'
|
import Block from '~/components/pub/my-ui/form/block.vue'
|
||||||
import Combobox from '~/components/pub/my-ui/form/combobox.vue'
|
import Combobox from '~/components/pub/my-ui/combobox/combobox.vue'
|
||||||
import FieldGroup from '~/components/pub/my-ui/form/field-group.vue'
|
import FieldGroup from '~/components/pub/my-ui/form/field-group.vue'
|
||||||
import Field from '~/components/pub/my-ui/form/field.vue'
|
import Field from '~/components/pub/my-ui/form/field.vue'
|
||||||
import Label from '~/components/pub/my-ui/form/label.vue'
|
import Label from '~/components/pub/my-ui/form/label.vue'
|
||||||
|
|||||||
@@ -51,7 +51,7 @@ defineProps<Props>()
|
|||||||
<DE.Cell>
|
<DE.Cell>
|
||||||
<DE.Label>DPJP</DE.Label>
|
<DE.Label>DPJP</DE.Label>
|
||||||
<DE.Field>
|
<DE.Field>
|
||||||
{{ item.doctor.employee.person.name }}
|
{{ item.doctor?.employee?.person.name }}
|
||||||
</DE.Field>
|
</DE.Field>
|
||||||
</DE.Cell>
|
</DE.Cell>
|
||||||
<DE.Cell>
|
<DE.Cell>
|
||||||
|
|||||||
@@ -0,0 +1,108 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
// Components
|
||||||
|
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'
|
||||||
|
import Button from '~/components/pub/ui/button/Button.vue'
|
||||||
|
|
||||||
|
// Constants
|
||||||
|
import { infraGroupCodesKeys } from "~/lib/constants"
|
||||||
|
|
||||||
|
// Types
|
||||||
|
import type { InfraFormData } from '~/schemas/infra.schema'
|
||||||
|
|
||||||
|
// Helpers
|
||||||
|
import type z from 'zod'
|
||||||
|
import { useForm } from 'vee-validate'
|
||||||
|
import { toTypedSchema } from '@vee-validate/zod'
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
schema: z.ZodSchema<any>
|
||||||
|
values: any
|
||||||
|
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: InfraFormData, resetForm: () => void]
|
||||||
|
cancel: [resetForm: () => void]
|
||||||
|
}>()
|
||||||
|
|
||||||
|
const { defineField, errors, meta } = useForm({
|
||||||
|
validationSchema: toTypedSchema(props.schema),
|
||||||
|
initialValues: {
|
||||||
|
code: '',
|
||||||
|
name: '',
|
||||||
|
infraGroup_code: infraGroupCodesKeys['public-screen'],
|
||||||
|
parent_id: null,
|
||||||
|
} as Partial<InfraFormData>,
|
||||||
|
})
|
||||||
|
|
||||||
|
const [code, codeAttrs] = defineField('code')
|
||||||
|
const [name, nameAttrs] = defineField('name')
|
||||||
|
const [infraGroup_code] = defineField('infraGroup_code')
|
||||||
|
const [parent_id] = defineField('parent_id')
|
||||||
|
|
||||||
|
if (props.values) {
|
||||||
|
if (props.values.code !== undefined) code.value = props.values.code
|
||||||
|
if (props.values.name !== undefined) name.value = props.values.name
|
||||||
|
if (props.values.infraGroup_code !== undefined) infraGroup_code.value = props.values.infraGroup_code
|
||||||
|
if (props.values.parent_id !== undefined) parent_id.value = props.values.parent_id
|
||||||
|
}
|
||||||
|
|
||||||
|
const resetForm = () => {
|
||||||
|
code.value = ''
|
||||||
|
name.value = ''
|
||||||
|
infraGroup_code.value = infraGroupCodesKeys['public-screen']
|
||||||
|
parent_id.value = null
|
||||||
|
}
|
||||||
|
|
||||||
|
function onSubmitForm() {
|
||||||
|
const formData: InfraFormData = {
|
||||||
|
code: code.value || '',
|
||||||
|
name: name.value || '',
|
||||||
|
infraGroup_code: infraGroup_code.value || infraGroupCodesKeys['public-screen'],
|
||||||
|
parent_id: parent_id.value || null,
|
||||||
|
}
|
||||||
|
emit('submit', formData, resetForm)
|
||||||
|
}
|
||||||
|
|
||||||
|
function onCancelForm() {
|
||||||
|
emit('cancel', resetForm)
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<form id="form-building" @submit.prevent>
|
||||||
|
<Block labelSize="thin" class="!mb-2.5 !pt-0 xl:!mb-3" :colCount="1">
|
||||||
|
<Cell>
|
||||||
|
<Label height="compact">Kode</Label>
|
||||||
|
<Field :errMessage="errors.code">
|
||||||
|
<Input id="code" v-model="code" v-bind="codeAttrs" :disabled="isLoading || isReadonly" />
|
||||||
|
</Field>
|
||||||
|
</Cell>
|
||||||
|
<Cell>
|
||||||
|
<Label height="compact">Nama</Label>
|
||||||
|
<Field :errMessage="errors.name">
|
||||||
|
<Input id="name" v-model="name" v-bind="nameAttrs" :disabled="isLoading || isReadonly" />
|
||||||
|
</Field>
|
||||||
|
</Cell>
|
||||||
|
</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,37 @@
|
|||||||
|
import type {
|
||||||
|
Col,
|
||||||
|
KeyLabel,
|
||||||
|
RecComponent,
|
||||||
|
RecStrFuncComponent,
|
||||||
|
RecStrFuncUnknown,
|
||||||
|
Th,
|
||||||
|
} from '~/components/pub/my-ui/data/types'
|
||||||
|
import { defineAsyncComponent } from 'vue'
|
||||||
|
|
||||||
|
const action = defineAsyncComponent(() => import('~/components/pub/my-ui/data/dropdown-action-dud.vue'))
|
||||||
|
|
||||||
|
export const cols: Col[] = [{}, {}, { width: 50 }]
|
||||||
|
|
||||||
|
export const header: Th[][] = [[{ label: 'Kode' }, { label: 'Nama' }, { label: '' }]]
|
||||||
|
|
||||||
|
export const keys = ['code', 'name', 'action']
|
||||||
|
|
||||||
|
export const delKeyNames: KeyLabel[] = [
|
||||||
|
{ key: 'code', label: 'Kode' },
|
||||||
|
{ key: 'name', label: 'Nama' },
|
||||||
|
]
|
||||||
|
|
||||||
|
export const funcParsed: RecStrFuncUnknown = {}
|
||||||
|
|
||||||
|
export const funcComponent: RecStrFuncComponent = {
|
||||||
|
action(rec, idx) {
|
||||||
|
const res: RecComponent = {
|
||||||
|
idx,
|
||||||
|
rec: rec as object,
|
||||||
|
component: action,
|
||||||
|
}
|
||||||
|
return res
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
export const funcHtml: RecStrFuncUnknown = {}
|
||||||
@@ -0,0 +1,41 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
// Components
|
||||||
|
import PaginationView from '~/components/pub/my-ui/pagination/pagination-view.vue'
|
||||||
|
|
||||||
|
// Types
|
||||||
|
import type { PaginationMeta } from '~/components/pub/my-ui/pagination/pagination.type'
|
||||||
|
|
||||||
|
// Configs
|
||||||
|
import { cols, funcComponent, funcHtml, funcParsed, header, keys } from './list-cfg'
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
data: any[]
|
||||||
|
paginationMeta: PaginationMeta
|
||||||
|
}
|
||||||
|
|
||||||
|
defineProps<Props>()
|
||||||
|
|
||||||
|
const emit = defineEmits<{
|
||||||
|
pageChange: [page: number]
|
||||||
|
}>()
|
||||||
|
|
||||||
|
function handlePageChange(page: number) {
|
||||||
|
emit('pageChange', page)
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="space-y-4">
|
||||||
|
<PubMyUiDataTable
|
||||||
|
:rows="data"
|
||||||
|
:cols="cols"
|
||||||
|
:header="header"
|
||||||
|
:keys="keys"
|
||||||
|
:func-parsed="funcParsed"
|
||||||
|
:func-html="funcHtml"
|
||||||
|
:func-component="funcComponent"
|
||||||
|
:skeleton-size="paginationMeta?.pageSize"
|
||||||
|
/>
|
||||||
|
<PaginationView :pagination-meta="paginationMeta" @page-change="handlePageChange" />
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
@@ -5,7 +5,7 @@ import Cell from '~/components/pub/my-ui/doc-entry/cell.vue'
|
|||||||
import Field from '~/components/pub/my-ui/doc-entry/field.vue'
|
import Field from '~/components/pub/my-ui/doc-entry/field.vue'
|
||||||
import Label from '~/components/pub/my-ui/doc-entry/label.vue'
|
import Label from '~/components/pub/my-ui/doc-entry/label.vue'
|
||||||
import Button from '~/components/pub/ui/button/Button.vue'
|
import Button from '~/components/pub/ui/button/Button.vue'
|
||||||
import Combobox from '~/components/pub/my-ui/form/combobox.vue'
|
import Combobox from '~/components/pub/my-ui/combobox/combobox.vue'
|
||||||
|
|
||||||
// Constants
|
// Constants
|
||||||
import { infraGroupCodesKeys } from '~/lib/constants'
|
import { infraGroupCodesKeys } from '~/lib/constants'
|
||||||
@@ -65,12 +65,12 @@ if (props.values) {
|
|||||||
if (props.values.name !== undefined) name.value = props.values.name
|
if (props.values.name !== undefined) name.value = props.values.name
|
||||||
if (props.values.infraGroup_code !== undefined) infraGroup_code.value = props.values.infraGroup_code
|
if (props.values.infraGroup_code !== undefined) infraGroup_code.value = props.values.infraGroup_code
|
||||||
if (props.values.specialist_id !== undefined)
|
if (props.values.specialist_id !== undefined)
|
||||||
specialist_id.value = props.values.specialist_id ? String(props.values.specialist_id) : null
|
specialist_id.value = props.values.specialist_id ? Number(props.values.specialist_id) : null
|
||||||
if (props.values.subspecialist_id !== undefined)
|
if (props.values.subspecialist_id !== undefined)
|
||||||
subspecialist_id.value = props.values.subspecialist_id ? String(props.values.subspecialist_id) : null
|
subspecialist_id.value = props.values.subspecialist_id ? Number(props.values.subspecialist_id) : null
|
||||||
if (props.values.unit_id !== undefined) unit_id.value = props.values.unit_id ? String(props.values.unit_id) : null
|
if (props.values.unit_id !== undefined) unit_id.value = props.values.unit_id ? Number(props.values.unit_id) : null
|
||||||
if (props.values.parent_id !== undefined)
|
if (props.values.parent_id !== undefined)
|
||||||
parent_id.value = props.values.parent_id ? String(props.values.parent_id) : null
|
parent_id.value = props.values.parent_id ? Number(props.values.parent_id) : null
|
||||||
}
|
}
|
||||||
|
|
||||||
const resetForm = () => {
|
const resetForm = () => {
|
||||||
@@ -102,18 +102,50 @@ function onCancelForm() {
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<form id="form-building" @submit.prevent>
|
<form
|
||||||
<Block labelSize="thin" class="!mb-2.5 !pt-0 xl:!mb-3" :colCount="1">
|
id="form-building"
|
||||||
|
@submit.prevent
|
||||||
|
>
|
||||||
|
<Block
|
||||||
|
labelSize="thin"
|
||||||
|
class="!mb-2.5 !pt-0 xl:!mb-3"
|
||||||
|
:colCount="1"
|
||||||
|
>
|
||||||
<Cell>
|
<Cell>
|
||||||
<Label height="compact">Kode</Label>
|
<Label height="compact">Kode</Label>
|
||||||
<Field :errMessage="errors.code">
|
<Field :errMessage="errors.code">
|
||||||
<Input id="code" v-model="code" v-bind="codeAttrs" :disabled="isLoading || isReadonly" />
|
<Input
|
||||||
|
id="code"
|
||||||
|
v-model="code"
|
||||||
|
v-bind="codeAttrs"
|
||||||
|
:disabled="isLoading || isReadonly"
|
||||||
|
/>
|
||||||
</Field>
|
</Field>
|
||||||
</Cell>
|
</Cell>
|
||||||
<Cell>
|
<Cell>
|
||||||
<Label height="compact">Nama</Label>
|
<Label height="compact">Nama</Label>
|
||||||
<Field :errMessage="errors.name">
|
<Field :errMessage="errors.name">
|
||||||
<Input id="name" v-model="name" v-bind="nameAttrs" :disabled="isLoading || isReadonly" />
|
<Input
|
||||||
|
id="name"
|
||||||
|
v-model="name"
|
||||||
|
v-bind="nameAttrs"
|
||||||
|
:disabled="isLoading || isReadonly"
|
||||||
|
/>
|
||||||
|
</Field>
|
||||||
|
</Cell>
|
||||||
|
<Cell>
|
||||||
|
<Label height="compact">Lantai</Label>
|
||||||
|
<Field :errMessage="errors.parent_id">
|
||||||
|
<Combobox
|
||||||
|
id="parent"
|
||||||
|
v-model="parent_id"
|
||||||
|
v-bind="parentAttrs"
|
||||||
|
:items="parents"
|
||||||
|
:is-disabled="isLoading || isReadonly"
|
||||||
|
placeholder="Pilih Lantai"
|
||||||
|
search-placeholder="Cari Lantai"
|
||||||
|
empty-message="Lantai tidak ditemukan"
|
||||||
|
/>
|
||||||
</Field>
|
</Field>
|
||||||
</Cell>
|
</Cell>
|
||||||
<Cell>
|
<Cell>
|
||||||
@@ -124,7 +156,7 @@ function onCancelForm() {
|
|||||||
v-model="unit_id"
|
v-model="unit_id"
|
||||||
v-bind="unitAttrs"
|
v-bind="unitAttrs"
|
||||||
:items="units"
|
:items="units"
|
||||||
:disabled="isLoading || isReadonly"
|
:is-disabled="isLoading || isReadonly"
|
||||||
placeholder="Pilih Unit"
|
placeholder="Pilih Unit"
|
||||||
search-placeholder="Cari Unit"
|
search-placeholder="Cari Unit"
|
||||||
empty-message="Unit tidak ditemukan"
|
empty-message="Unit tidak ditemukan"
|
||||||
@@ -140,7 +172,7 @@ function onCancelForm() {
|
|||||||
v-model="specialist_id"
|
v-model="specialist_id"
|
||||||
v-bind="specialistAttrs"
|
v-bind="specialistAttrs"
|
||||||
:items="specialists"
|
:items="specialists"
|
||||||
:disabled="isLoading || isReadonly"
|
:is-disabled="isLoading || isReadonly"
|
||||||
placeholder="Pilih Spesialis"
|
placeholder="Pilih Spesialis"
|
||||||
search-placeholder="Cari spesialis"
|
search-placeholder="Cari spesialis"
|
||||||
empty-message="Spesialis tidak ditemukan"
|
empty-message="Spesialis tidak ditemukan"
|
||||||
@@ -156,31 +188,23 @@ function onCancelForm() {
|
|||||||
v-model="subspecialist_id"
|
v-model="subspecialist_id"
|
||||||
v-bind="subspecialistAttrs"
|
v-bind="subspecialistAttrs"
|
||||||
:items="subspecialists"
|
:items="subspecialists"
|
||||||
:disabled="isLoading || isReadonly"
|
:is-disabled="isLoading || isReadonly"
|
||||||
placeholder="Pilih Sub Spesialis"
|
placeholder="Pilih Sub Spesialis"
|
||||||
search-placeholder="Cari sub spesialis"
|
search-placeholder="Cari sub spesialis"
|
||||||
empty-message="Sub Spesialis tidak ditemukan"
|
empty-message="Sub Spesialis tidak ditemukan"
|
||||||
/>
|
/>
|
||||||
</Field>
|
</Field>
|
||||||
</Cell>
|
</Cell>
|
||||||
<Cell>
|
|
||||||
<Label height="compact">Lantai</Label>
|
|
||||||
<Field :errMessage="errors.parent_id">
|
|
||||||
<Combobox
|
|
||||||
id="parent"
|
|
||||||
v-model="parent_id"
|
|
||||||
v-bind="parentAttrs"
|
|
||||||
:items="parents"
|
|
||||||
:disabled="isLoading || isReadonly"
|
|
||||||
placeholder="Pilih Lantai"
|
|
||||||
search-placeholder="Cari Lantai"
|
|
||||||
empty-message="Lantai tidak ditemukan"
|
|
||||||
/>
|
|
||||||
</Field>
|
|
||||||
</Cell>
|
|
||||||
</Block>
|
</Block>
|
||||||
<div class="my-2 flex justify-end gap-2 py-2">
|
<div class="my-2 flex justify-end gap-2 py-2">
|
||||||
<Button type="button" variant="secondary" class="w-[120px]" @click="onCancelForm"> Kembali </Button>
|
<Button
|
||||||
|
type="button"
|
||||||
|
variant="secondary"
|
||||||
|
class="w-[120px]"
|
||||||
|
@click="onCancelForm"
|
||||||
|
>
|
||||||
|
Kembali
|
||||||
|
</Button>
|
||||||
<Button
|
<Button
|
||||||
v-if="!isReadonly"
|
v-if="!isReadonly"
|
||||||
type="button"
|
type="button"
|
||||||
|
|||||||
@@ -14,18 +14,9 @@ const action = defineAsyncComponent(() => import('~/components/pub/my-ui/data/dr
|
|||||||
|
|
||||||
export const cols: Col[] = [{}, {}, {}, {}, {}, { width: 50 }]
|
export const cols: Col[] = [{}, {}, {}, {}, {}, { width: 50 }]
|
||||||
|
|
||||||
export const header: Th[][] = [
|
export const header: Th[][] = [[{ label: 'Kode' }, { label: 'Nama' }, { label: 'Lantai' }, { label: '' }]]
|
||||||
[
|
|
||||||
{ label: 'Kode' },
|
|
||||||
{ label: 'Nama' },
|
|
||||||
{ label: 'Spesialis' },
|
|
||||||
{ label: 'Sub Spesialis' },
|
|
||||||
{ label: 'Unit' },
|
|
||||||
{ label: '' },
|
|
||||||
],
|
|
||||||
]
|
|
||||||
|
|
||||||
export const keys = ['code', 'name', 'specialist', 'subspecialist', 'unit', 'action']
|
export const keys = ['code', 'name', 'parent', 'action']
|
||||||
|
|
||||||
export const delKeyNames: KeyLabel[] = [
|
export const delKeyNames: KeyLabel[] = [
|
||||||
{ key: 'code', label: 'Kode' },
|
{ key: 'code', label: 'Kode' },
|
||||||
@@ -45,6 +36,10 @@ export const funcParsed: RecStrFuncUnknown = {
|
|||||||
const recX = rec as SmallDetailDto
|
const recX = rec as SmallDetailDto
|
||||||
return recX.unit?.name || '-'
|
return recX.unit?.name || '-'
|
||||||
},
|
},
|
||||||
|
parent: (rec: unknown): unknown => {
|
||||||
|
const recX = rec as SmallDetailDto
|
||||||
|
return recX.parent?.name || '-'
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
export const funcComponent: RecStrFuncComponent = {
|
export const funcComponent: RecStrFuncComponent = {
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ import { Label } from '~/components/pub/ui/label'
|
|||||||
import Select from '~/components/pub/ui/select/Select.vue'
|
import Select from '~/components/pub/ui/select/Select.vue'
|
||||||
import { RadioGroup, RadioGroupItem } from '~/components/pub/ui/radio-group'
|
import { RadioGroup, RadioGroupItem } from '~/components/pub/ui/radio-group'
|
||||||
import { Textarea } from '~/components/pub/ui/textarea'
|
import { Textarea } from '~/components/pub/ui/textarea'
|
||||||
import DatepickerSingle from '~/components/pub/my-ui/form/datepicker-single.vue'
|
import DatepickerSingle from '~/components/pub/my-ui/datepicker/datepicker-single.vue'
|
||||||
|
|
||||||
const emit = defineEmits<{
|
const emit = defineEmits<{
|
||||||
(e: 'event', value: any): void
|
(e: 'event', value: any): void
|
||||||
|
|||||||
@@ -2,12 +2,12 @@
|
|||||||
import type { FormErrors } from '~/types/error'
|
import type { FormErrors } from '~/types/error'
|
||||||
import { toTypedSchema } from '@vee-validate/zod'
|
import { toTypedSchema } from '@vee-validate/zod'
|
||||||
import Block from '~/components/pub/my-ui/form/block.vue'
|
import Block from '~/components/pub/my-ui/form/block.vue'
|
||||||
import Combobox from '~/components/pub/my-ui/form/combobox.vue'
|
import Combobox from '~/components/pub/my-ui/combobox/combobox.vue'
|
||||||
import FieldGroup from '~/components/pub/my-ui/form/field-group.vue'
|
import FieldGroup from '~/components/pub/my-ui/form/field-group.vue'
|
||||||
import Field from '~/components/pub/my-ui/form/field.vue'
|
import Field from '~/components/pub/my-ui/form/field.vue'
|
||||||
import Label from '~/components/pub/my-ui/form/label.vue'
|
import Label from '~/components/pub/my-ui/form/label.vue'
|
||||||
import { Form } from '~/components/pub/ui/form'
|
import { Form } from '~/components/pub/ui/form'
|
||||||
import DatepickerSingle from '~/components/pub/my-ui/form/datepicker-single.vue'
|
import DatepickerSingle from '~/components/pub/my-ui/datepicker/datepicker-single.vue'
|
||||||
|
|
||||||
import { educationCodes, genderCodes, occupationCodes, religionCodes, relationshipCodes } from '~/lib/constants'
|
import { educationCodes, genderCodes, occupationCodes, religionCodes, relationshipCodes } from '~/lib/constants'
|
||||||
import { mapToComboboxOptList } from '~/lib/utils'
|
import { mapToComboboxOptList } from '~/lib/utils'
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ref } from 'vue'
|
|
||||||
import Block from '~/components/pub/my-ui/doc-entry/block.vue'
|
import Block from '~/components/pub/my-ui/doc-entry/block.vue'
|
||||||
import Cell from '~/components/pub/my-ui/doc-entry/cell.vue'
|
import Cell from '~/components/pub/my-ui/doc-entry/cell.vue'
|
||||||
import Field from '~/components/pub/my-ui/doc-entry/field.vue'
|
import Field from '~/components/pub/my-ui/doc-entry/field.vue'
|
||||||
@@ -9,6 +8,8 @@ const props = defineProps<{
|
|||||||
excludeFields?: string[]
|
excludeFields?: string[]
|
||||||
}>()
|
}>()
|
||||||
|
|
||||||
|
const emits = defineEmits(['click'])
|
||||||
|
|
||||||
const subject = ref({
|
const subject = ref({
|
||||||
'prim-compl': '',
|
'prim-compl': '',
|
||||||
'sec-compl': '',
|
'sec-compl': '',
|
||||||
@@ -25,77 +26,329 @@ const isExcluded = (key: string) => props.excludeFields?.includes(key)
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="space-y-4">
|
<form id="entry-form">
|
||||||
<!-- Keluhan Utama -->
|
<div class="mb-5 border-b border-b-slate-300 pb-3 text-lg xl:text-xl">
|
||||||
<Cell v-if="!isExcluded('prim-compl')">
|
<div>
|
||||||
<Label dynamic>Keluhan Utama</Label>
|
<h1 class="font-semibold">Pemeriksaan Fisiatrik</h1>
|
||||||
<Field>
|
<span class="text-sm font-semibold">Anamnesa</span>
|
||||||
<Textarea placeholder="Masukkan anamnesa pasien" v-model="subject['prim-compl']" />
|
</div>
|
||||||
</Field>
|
<div class="my-2 rounded-md border border-slate-300 p-4">
|
||||||
</Cell>
|
<Block>
|
||||||
|
<Cell>
|
||||||
|
<Label dynamic>Keluhan Utama</Label>
|
||||||
|
<Field>
|
||||||
|
<Textarea />
|
||||||
|
</Field>
|
||||||
|
</Cell>
|
||||||
|
</Block>
|
||||||
|
|
||||||
<!-- Keluhan Tambahan -->
|
<Block :colCount="3">
|
||||||
<Cell v-if="!isExcluded('sec-compl')">
|
<Cell>
|
||||||
<Label dynamic>Keluhan Tambahan</Label>
|
<Label dynamic>Diagnosa Medis</Label>
|
||||||
<Field>
|
<Field>
|
||||||
<Textarea placeholder="Masukkan keluhan tambahan" v-model="subject['sec-compl']" />
|
<Textarea />
|
||||||
</Field>
|
</Field>
|
||||||
</Cell>
|
</Cell>
|
||||||
|
|
||||||
<!-- Riwayat Penyakit Sekarang -->
|
<Cell>
|
||||||
<Cell v-if="!isExcluded('cur-disea-hist')">
|
<Label dynamic>Rencana Awal Medis</Label>
|
||||||
<Label dynamic>Riwayat Penyakit Sekarang</Label>
|
<Field>
|
||||||
<Field>
|
<Textarea />
|
||||||
<Textarea placeholder="Masukkan riwayat penyakit sekarang" v-model="subject['cur-disea-hist']" />
|
</Field>
|
||||||
</Field>
|
</Cell>
|
||||||
</Cell>
|
|
||||||
|
|
||||||
<!-- Riwayat Penyakit Dahulu -->
|
<Cell>
|
||||||
<Cell v-if="!isExcluded('pas-disea-hist')">
|
<Label dynamic>Terapi</Label>
|
||||||
<Label dynamic>Riwayat Penyakit Dahulu</Label>
|
<Field>
|
||||||
<Field>
|
<Textarea />
|
||||||
<Textarea placeholder="Masukkan riwayat penyakit dahulu" v-model="subject['pas-disea-hist']" />
|
</Field>
|
||||||
</Field>
|
</Cell>
|
||||||
</Cell>
|
</Block>
|
||||||
|
</div>
|
||||||
|
<Separator class="mt-8" />
|
||||||
|
|
||||||
<!-- Riwayat Penyakit Keluarga -->
|
<div class="my-2">
|
||||||
<Cell v-if="!isExcluded('fam-disea-hist')">
|
<h1 class="font-semibold">Pemeriksaan Fisik</h1>
|
||||||
<Label dynamic>Riwayat Penyakit Keluarga</Label>
|
<span class="text-sm font-semibold">Status Generalis</span>
|
||||||
<Field>
|
</div>
|
||||||
<Textarea placeholder="Masukkan riwayat penyakit keluarga" v-model="subject['fam-disea-hist']" />
|
|
||||||
</Field>
|
|
||||||
</Cell>
|
|
||||||
|
|
||||||
<!-- Riwayat Alergi -->
|
<div class="my-2 rounded-md border border-slate-300 p-4">
|
||||||
<Cell v-if="!isExcluded('alg-hist')">
|
<Block :colCount="3">
|
||||||
<Label dynamic>Riwayat Alergi</Label>
|
<Cell>
|
||||||
<Field>
|
<Label dynamic>Tekanan Darah</Label>
|
||||||
<Textarea placeholder="Masukkan riwayat alergi" v-model="subject['alg-hist']" />
|
<Field>
|
||||||
</Field>
|
<Input placeholder="Sistolik" />
|
||||||
</Cell>
|
<Input placeholder="Diastolik" />
|
||||||
|
</Field>
|
||||||
|
</Cell>
|
||||||
|
|
||||||
<!-- Reaksi Alergi -->
|
<Cell>
|
||||||
<Cell v-if="!isExcluded('alg-react')">
|
<Label dynamic>Nadi</Label>
|
||||||
<Label dynamic>Reaksi Alergi</Label>
|
<Field>
|
||||||
<Field>
|
<Input />
|
||||||
<Textarea placeholder="Masukkan reaksi alergi" v-model="subject['alg-react']" />
|
</Field>
|
||||||
</Field>
|
</Cell>
|
||||||
</Cell>
|
|
||||||
|
|
||||||
<!-- Pengobatan yang Sedang Dijalani -->
|
<Cell>
|
||||||
<Cell v-if="!isExcluded('med-hist')">
|
<Label dynamic>GCS</Label>
|
||||||
<Label dynamic>Riwayat Pengobatan</Label>
|
<Field>
|
||||||
<Field>
|
<Input />
|
||||||
<Textarea placeholder="Masukkan pengobatan yang sedang dijalani" v-model="subject['med-hist']" />
|
</Field>
|
||||||
</Field>
|
</Cell>
|
||||||
</Cell>
|
</Block>
|
||||||
|
<Block :colCount="3">
|
||||||
|
<Cell>
|
||||||
|
<Label dynamic>RR</Label>
|
||||||
|
<Field>
|
||||||
|
<Input />
|
||||||
|
</Field>
|
||||||
|
</Cell>
|
||||||
|
|
||||||
<!-- Golongan Darah -->
|
<Cell>
|
||||||
<Cell v-if="!isExcluded('blood-type')">
|
<Label dynamic>Ambulasi</Label>
|
||||||
<Label dynamic>Golongan Darah</Label>
|
<Field>
|
||||||
<Field>
|
<RadioGroup class="flex gap-4">
|
||||||
<Input type="text" placeholder="Masukkan golongan darah" v-model="subject['blood-type']" />
|
<div class="flex items-center space-x-2">
|
||||||
</Field>
|
<RadioGroupItem
|
||||||
</Cell>
|
id="vaksin-yes"
|
||||||
</div>
|
value="yes"
|
||||||
|
/>
|
||||||
|
<Label for="vaksin-yes">Dependent</Label>
|
||||||
|
</div>
|
||||||
|
<div class="flex items-center space-x-2">
|
||||||
|
<RadioGroupItem
|
||||||
|
id="vaksin-no"
|
||||||
|
value="no"
|
||||||
|
/>
|
||||||
|
<Label for="vaksin-no">Independen</Label>
|
||||||
|
</div>
|
||||||
|
</RadioGroup>
|
||||||
|
</Field>
|
||||||
|
</Cell>
|
||||||
|
|
||||||
|
<Cell>
|
||||||
|
<Label dynamic>Gait</Label>
|
||||||
|
<Field>
|
||||||
|
<Textarea />
|
||||||
|
</Field>
|
||||||
|
</Cell>
|
||||||
|
</Block>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="my-2">
|
||||||
|
<span class="text-sm font-semibold">Status Neurologis</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="my-2 rounded-md border border-slate-300 p-4">
|
||||||
|
<Block :colCount="3">
|
||||||
|
<Cell>
|
||||||
|
<Label dynamic>N. Cranialis</Label>
|
||||||
|
<Field>
|
||||||
|
<Input />
|
||||||
|
</Field>
|
||||||
|
</Cell>
|
||||||
|
|
||||||
|
<Cell>
|
||||||
|
<Label dynamic>Sensoris</Label>
|
||||||
|
<Field>
|
||||||
|
<Input />
|
||||||
|
</Field>
|
||||||
|
</Cell>
|
||||||
|
|
||||||
|
<Cell>
|
||||||
|
<Label dynamic>Reflek Fisilogis</Label>
|
||||||
|
<Field>
|
||||||
|
<Input />
|
||||||
|
</Field>
|
||||||
|
</Cell>
|
||||||
|
</Block>
|
||||||
|
<Block :colCount="2">
|
||||||
|
<Cell>
|
||||||
|
<Label dynamic>Reflek Patologis</Label>
|
||||||
|
<Field>
|
||||||
|
<Input />
|
||||||
|
</Field>
|
||||||
|
</Cell>
|
||||||
|
<Cell>
|
||||||
|
<Label dynamic>Saraf Otonom</Label>
|
||||||
|
<Field>
|
||||||
|
<Input />
|
||||||
|
</Field>
|
||||||
|
</Cell>
|
||||||
|
</Block>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="my-2">
|
||||||
|
<span class="text-sm font-semibold">Status Muskuloskeletal - ROM</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="my-2 rounded-md border border-slate-300 p-4">
|
||||||
|
<Block :colCount="2">
|
||||||
|
<Cell>
|
||||||
|
<Label dynamic>Leher</Label>
|
||||||
|
<Field>
|
||||||
|
<Input />
|
||||||
|
</Field>
|
||||||
|
</Cell>
|
||||||
|
<Cell>
|
||||||
|
<Label dynamic>Batang Tubuh</Label>
|
||||||
|
<Field>
|
||||||
|
<Input />
|
||||||
|
</Field>
|
||||||
|
</Cell>
|
||||||
|
</Block>
|
||||||
|
<Block :colCount="2">
|
||||||
|
<Cell>
|
||||||
|
<Label dynamic>AGA</Label>
|
||||||
|
<Field>
|
||||||
|
<Input />
|
||||||
|
</Field>
|
||||||
|
</Cell>
|
||||||
|
<Cell>
|
||||||
|
<Label dynamic>AGB</Label>
|
||||||
|
<Field>
|
||||||
|
<Input />
|
||||||
|
</Field>
|
||||||
|
</Cell>
|
||||||
|
</Block>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="my-2">
|
||||||
|
<span class="text-sm font-semibold">Status Muskuloskeletal - MMT</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="my-2 rounded-md border border-slate-300 p-4">
|
||||||
|
<Block :colCount="2">
|
||||||
|
<Cell>
|
||||||
|
<Label dynamic>Leher</Label>
|
||||||
|
<Field>
|
||||||
|
<Input />
|
||||||
|
</Field>
|
||||||
|
</Cell>
|
||||||
|
<Cell>
|
||||||
|
<Label dynamic>Batang Tubuh</Label>
|
||||||
|
<Field>
|
||||||
|
<Input />
|
||||||
|
</Field>
|
||||||
|
</Cell>
|
||||||
|
</Block>
|
||||||
|
<Block :colCount="2">
|
||||||
|
<Cell>
|
||||||
|
<Label dynamic>AGA</Label>
|
||||||
|
<Field>
|
||||||
|
<Input />
|
||||||
|
</Field>
|
||||||
|
</Cell>
|
||||||
|
<Cell>
|
||||||
|
<Label dynamic>AGB</Label>
|
||||||
|
<Field>
|
||||||
|
<Input />
|
||||||
|
</Field>
|
||||||
|
</Cell>
|
||||||
|
</Block>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="my-2">
|
||||||
|
<span class="text-sm font-semibold">Statu Lokalis</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<Block>
|
||||||
|
<Cell>
|
||||||
|
<Label dynamic>Deskripsi Temuan Fisik</Label>
|
||||||
|
<Field>
|
||||||
|
<Textarea />
|
||||||
|
</Field>
|
||||||
|
</Cell>
|
||||||
|
</Block>
|
||||||
|
|
||||||
|
<Separator class="mt-8" />
|
||||||
|
|
||||||
|
<div class="my-2">
|
||||||
|
<h1 class="font-semibold">Pemeriksaan Penunjang</h1>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<Block>
|
||||||
|
<Cell>
|
||||||
|
<Label dynamic>Catatan Pemeriksaan Penunjang</Label>
|
||||||
|
<Field>
|
||||||
|
<Textarea />
|
||||||
|
</Field>
|
||||||
|
</Cell>
|
||||||
|
</Block>
|
||||||
|
|
||||||
|
<Separator class="mt-8" />
|
||||||
|
|
||||||
|
<div class="my-2">
|
||||||
|
<h1 class="font-semibold">Daftar Masalah</h1>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<Block :colCount="2">
|
||||||
|
<Cell>
|
||||||
|
<Label dynamic>Masalah Medik</Label>
|
||||||
|
<Field>
|
||||||
|
<Textarea />
|
||||||
|
</Field>
|
||||||
|
</Cell>
|
||||||
|
<Cell>
|
||||||
|
<Label dynamic>Masalah Rehabilitasi Medik</Label>
|
||||||
|
<Field>
|
||||||
|
<Textarea />
|
||||||
|
</Field>
|
||||||
|
</Cell>
|
||||||
|
</Block>
|
||||||
|
|
||||||
|
<Separator class="mt-8" />
|
||||||
|
|
||||||
|
<div class="my-2">
|
||||||
|
<h1 class="font-semibold">Diagnosa Fungsional (ICD-X)</h1>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="mb-8 grid grid-cols-2 gap-4">
|
||||||
|
<AppIcdPreview />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="my-2">
|
||||||
|
<h1 class="font-semibold">Program Rehabilitasi</h1>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="my-2 rounded-md border border-slate-300 p-4">
|
||||||
|
<Block :colCount="3">
|
||||||
|
<Cell>
|
||||||
|
<Label dynamic>Modalitas Fisik</Label>
|
||||||
|
<Field>
|
||||||
|
<Textarea />
|
||||||
|
</Field>
|
||||||
|
</Cell>
|
||||||
|
|
||||||
|
<Cell>
|
||||||
|
<Label dynamic>Latihan</Label>
|
||||||
|
<Field>
|
||||||
|
<Textarea />
|
||||||
|
</Field>
|
||||||
|
</Cell>
|
||||||
|
|
||||||
|
<Cell>
|
||||||
|
<Label dynamic>Ortesa Protesa</Label>
|
||||||
|
<Field>
|
||||||
|
<Textarea />
|
||||||
|
</Field>
|
||||||
|
</Cell>
|
||||||
|
</Block>
|
||||||
|
<Block :colCount="2">
|
||||||
|
<Cell>
|
||||||
|
<Label dynamic>Edukasi</Label>
|
||||||
|
<Field>
|
||||||
|
<Textarea />
|
||||||
|
</Field>
|
||||||
|
</Cell>
|
||||||
|
<Cell>
|
||||||
|
<Label dynamic>Lain-Lain</Label>
|
||||||
|
<Field>
|
||||||
|
<Textarea />
|
||||||
|
</Field>
|
||||||
|
</Cell>
|
||||||
|
</Block>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@@ -1,172 +1,486 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import Block from '~/components/pub/my-ui/form/block.vue'
|
import Block from '~/components/pub/my-ui/doc-entry/block.vue'
|
||||||
import FieldGroup from '~/components/pub/my-ui/form/field-group.vue'
|
import Cell from '~/components/pub/my-ui/doc-entry/cell.vue'
|
||||||
import Field from '~/components/pub/my-ui/form/field.vue'
|
import Field from '~/components/pub/my-ui/doc-entry/field.vue'
|
||||||
import Label from '~/components/pub/my-ui/form/label.vue'
|
import Label from '~/components/pub/my-ui/doc-entry/label.vue'
|
||||||
|
|
||||||
|
const props = defineProps<{
|
||||||
|
excludeFields?: string[]
|
||||||
|
}>()
|
||||||
|
|
||||||
|
const emits = defineEmits(['click'])
|
||||||
|
|
||||||
|
const subject = ref({
|
||||||
|
'prim-compl': '',
|
||||||
|
'sec-compl': '',
|
||||||
|
'cur-disea-hist': '',
|
||||||
|
'pas-disea-hist': '',
|
||||||
|
'fam-disea-hist': '',
|
||||||
|
'alg-hist': '',
|
||||||
|
'alg-react': '',
|
||||||
|
'med-hist': '',
|
||||||
|
'blood-type': '',
|
||||||
|
})
|
||||||
|
|
||||||
|
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>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<form id="entry-form">
|
<form id="entry-form">
|
||||||
<div class="mb-5 border-b border-b-slate-300 pb-3 text-lg xl:text-xl">
|
<div class="mb-5 border-b border-b-slate-300 pb-3 text-lg xl:text-xl">
|
||||||
<Block>
|
<Block>
|
||||||
<FieldGroup>
|
<Cell>
|
||||||
<Label dynamic>Sudah Vaksin</Label>
|
|
||||||
<Field>
|
|
||||||
<Select
|
|
||||||
:options="[
|
|
||||||
{ label: 'Sudah', value: 'yes' },
|
|
||||||
{ label: 'Belum', value: 'no' },
|
|
||||||
]"
|
|
||||||
/>
|
|
||||||
</Field>
|
|
||||||
</FieldGroup>
|
|
||||||
|
|
||||||
<FieldGroup>
|
|
||||||
<Label dynamic>Kasus</Label>
|
|
||||||
<Field>
|
|
||||||
<Select
|
|
||||||
:options="[
|
|
||||||
{ label: 'Baru', value: 'baru' },
|
|
||||||
{ label: 'Lama', value: 'lama' },
|
|
||||||
]"
|
|
||||||
/>
|
|
||||||
</Field>
|
|
||||||
</FieldGroup>
|
|
||||||
|
|
||||||
<FieldGroup>
|
|
||||||
<Label dynamic>Kunjungan</Label>
|
|
||||||
<Field>
|
|
||||||
<Select
|
|
||||||
:options="[
|
|
||||||
{ label: 'Baru', value: 'baru' },
|
|
||||||
{ label: 'Lama', value: 'lama' },
|
|
||||||
]"
|
|
||||||
/>
|
|
||||||
</Field>
|
|
||||||
</FieldGroup>
|
|
||||||
|
|
||||||
<!-- Riwayat Penyakit -->
|
|
||||||
<FieldGroup :column="2">
|
|
||||||
<Label dynamic>Keluhan Utama</Label>
|
<Label dynamic>Keluhan Utama</Label>
|
||||||
<Field>
|
|
||||||
<Textarea placeholder="Masukkan anamnesa pasien" />
|
|
||||||
</Field>
|
|
||||||
</FieldGroup>
|
|
||||||
<FieldGroup :column="2">
|
|
||||||
<Label dynamic>Riwayat Penyakit</Label>
|
|
||||||
<Field>
|
|
||||||
<Textarea
|
|
||||||
placeholder="Masukkan anamnesa pasien (Riwayat Penyakit Sekarang, Dahulu, Pengobatan, Keluarga, dll)"
|
|
||||||
/>
|
|
||||||
</Field>
|
|
||||||
</FieldGroup>
|
|
||||||
|
|
||||||
<FieldGroup :column="2">
|
|
||||||
<Label dynamic>SpO₂</Label>
|
|
||||||
<Field>
|
|
||||||
<Input type="number" placeholder="%" />
|
|
||||||
</Field>
|
|
||||||
</FieldGroup>
|
|
||||||
|
|
||||||
<FieldGroup :column="2">
|
|
||||||
<Label dynamic>Tekanan Darah Sistol</Label>
|
|
||||||
<Field>
|
|
||||||
<Input type="number" placeholder="mmHg" />
|
|
||||||
</Field>
|
|
||||||
</FieldGroup>
|
|
||||||
|
|
||||||
<FieldGroup :column="2">
|
|
||||||
<Label dynamic>Tekanan Darah Diastol</Label>
|
|
||||||
<Field>
|
|
||||||
<Input type="number" placeholder="mmHg" />
|
|
||||||
</Field>
|
|
||||||
</FieldGroup>
|
|
||||||
|
|
||||||
<FieldGroup :column="2">
|
|
||||||
<Label dynamic>Respirasi</Label>
|
|
||||||
<Field>
|
|
||||||
<Input type="number" placeholder="kali/menit" />
|
|
||||||
</Field>
|
|
||||||
</FieldGroup>
|
|
||||||
|
|
||||||
<FieldGroup :column="2">
|
|
||||||
<Label dynamic>Nadi</Label>
|
|
||||||
<Field>
|
|
||||||
<Input type="number" placeholder="kali/menit" />
|
|
||||||
</Field>
|
|
||||||
</FieldGroup>
|
|
||||||
|
|
||||||
<FieldGroup :column="2">
|
|
||||||
<Label dynamic>Temperatur</Label>
|
|
||||||
<Field>
|
|
||||||
<Input type="number" placeholder="℃" />
|
|
||||||
</Field>
|
|
||||||
</FieldGroup>
|
|
||||||
|
|
||||||
<FieldGroup :column="2">
|
|
||||||
<Label dynamic>Berat Badan</Label>
|
|
||||||
<Field>
|
|
||||||
<Input type="number" placeholder="Kg" />
|
|
||||||
</Field>
|
|
||||||
</FieldGroup>
|
|
||||||
|
|
||||||
<FieldGroup :column="2">
|
|
||||||
<Label dynamic>Tinggi Badan</Label>
|
|
||||||
<Field>
|
|
||||||
<Input type="number" placeholder="Cm" />
|
|
||||||
</Field>
|
|
||||||
</FieldGroup>
|
|
||||||
|
|
||||||
<FieldGroup :column="2">
|
|
||||||
<Label dynamic>Golongan Darah</Label>
|
|
||||||
<Field>
|
|
||||||
<Select :options="bloodGroups" />
|
|
||||||
</Field>
|
|
||||||
</FieldGroup>
|
|
||||||
|
|
||||||
<FieldGroup :column="2">
|
|
||||||
<Label dynamic>Pemeriksaan Fisik (Yang Mendukung)</Label>
|
|
||||||
<Field>
|
|
||||||
<Textarea placeholder="Masukkan pemeriksaan fisik" />
|
|
||||||
</Field>
|
|
||||||
</FieldGroup>
|
|
||||||
|
|
||||||
<!-- Prosedur -->
|
|
||||||
<FieldGroup :column="2">
|
|
||||||
<Label dynamic>Diagnosa (ICD-X)</Label>
|
|
||||||
<Field>
|
|
||||||
<button class="rounded bg-orange-100 px-3 py-1 text-orange-600">+ Pilih Diagnosa</button>
|
|
||||||
</Field>
|
|
||||||
</FieldGroup>
|
|
||||||
<!-- Diagnosa -->
|
|
||||||
<FieldGroup :column="2">
|
|
||||||
<Label dynamic>Diagnosa (ICD-X)</Label>
|
|
||||||
<Field>
|
|
||||||
<button class="rounded bg-orange-100 px-3 py-1 text-orange-600">+ Pilih Diagnosa</button>
|
|
||||||
</Field>
|
|
||||||
</FieldGroup>
|
|
||||||
|
|
||||||
<FieldGroup :column="3">
|
|
||||||
<Label dynamic>Diagnosa Medis</Label>
|
|
||||||
<Field>
|
<Field>
|
||||||
<Textarea />
|
<Textarea />
|
||||||
</Field>
|
</Field>
|
||||||
</FieldGroup>
|
</Cell>
|
||||||
|
|
||||||
<FieldGroup :column="3">
|
|
||||||
<Label dynamic>Rencana Awal Medis</Label>
|
|
||||||
<Field>
|
|
||||||
<Textarea />
|
|
||||||
</Field>
|
|
||||||
</FieldGroup>
|
|
||||||
|
|
||||||
<FieldGroup :column="3">
|
|
||||||
<Label dynamic>Terapi</Label>
|
|
||||||
<Field>
|
|
||||||
<Textarea />
|
|
||||||
</Field>
|
|
||||||
</FieldGroup>
|
|
||||||
</Block>
|
</Block>
|
||||||
|
|
||||||
|
<Block :colCount="2">
|
||||||
|
<Cell>
|
||||||
|
<Label dynamic>Riwayat Penyakit Dahulu</Label>
|
||||||
|
<Field>
|
||||||
|
<Textarea />
|
||||||
|
</Field>
|
||||||
|
</Cell>
|
||||||
|
|
||||||
|
<Cell>
|
||||||
|
<Label dynamic>Riwayat Penyakit Sekarang</Label>
|
||||||
|
<Field>
|
||||||
|
<Textarea />
|
||||||
|
</Field>
|
||||||
|
</Cell>
|
||||||
|
</Block>
|
||||||
|
<Separator class="mt-8" />
|
||||||
|
|
||||||
|
<div class="my-2">
|
||||||
|
<h1 class="font-semibold">Pemeriksaan Fisik</h1>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<Block>
|
||||||
|
<Cell>
|
||||||
|
<Label dynamic>Umum</Label>
|
||||||
|
<Field>
|
||||||
|
<Input placeholder="Sistolik" />
|
||||||
|
</Field>
|
||||||
|
</Cell>
|
||||||
|
</Block>
|
||||||
|
|
||||||
|
<div class="my-2">
|
||||||
|
<h1 class="font-semibold">Tanda Vital</h1>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="my-2 rounded-md border border-slate-300 p-4">
|
||||||
|
<Block>
|
||||||
|
<Cell>
|
||||||
|
<Label dynamic>Kesadaran (GCS)</Label>
|
||||||
|
<Field>
|
||||||
|
<Input />
|
||||||
|
</Field>
|
||||||
|
</Cell>
|
||||||
|
</Block>
|
||||||
|
<Block :colCount="2">
|
||||||
|
<Cell>
|
||||||
|
<Label dynamic>Pernapasan</Label>
|
||||||
|
<Field>
|
||||||
|
<Input />
|
||||||
|
</Field>
|
||||||
|
</Cell>
|
||||||
|
|
||||||
|
<Cell>
|
||||||
|
<Label dynamic>Jenis</Label>
|
||||||
|
<Field>
|
||||||
|
<Input />
|
||||||
|
</Field>
|
||||||
|
</Cell>
|
||||||
|
</Block>
|
||||||
|
<Block :colCount="2">
|
||||||
|
<Cell>
|
||||||
|
<Label dynamic>Nadi</Label>
|
||||||
|
<Field>
|
||||||
|
<Input />
|
||||||
|
</Field>
|
||||||
|
</Cell>
|
||||||
|
<Cell>
|
||||||
|
<Label dynamic>Jenis</Label>
|
||||||
|
<Field>
|
||||||
|
<Input />
|
||||||
|
</Field>
|
||||||
|
</Cell>
|
||||||
|
</Block>
|
||||||
|
<Block :colCount="2">
|
||||||
|
<Cell>
|
||||||
|
<Label dynamic>Tekanan Darah Lengan Kanan</Label>
|
||||||
|
<Field>
|
||||||
|
<Input />
|
||||||
|
</Field>
|
||||||
|
</Cell>
|
||||||
|
<Cell>
|
||||||
|
<Label dynamic>Tekanan Darah Lengan Kiri</Label>
|
||||||
|
<Field>
|
||||||
|
<Input />
|
||||||
|
</Field>
|
||||||
|
</Cell>
|
||||||
|
</Block>
|
||||||
|
<Block :colCount="2">
|
||||||
|
<Cell>
|
||||||
|
<Label dynamic>Suhu Aksila</Label>
|
||||||
|
<Field>
|
||||||
|
<Input />
|
||||||
|
</Field>
|
||||||
|
</Cell>
|
||||||
|
<Cell>
|
||||||
|
<Label dynamic>Suhu Rektal</Label>
|
||||||
|
<Field>
|
||||||
|
<Input />
|
||||||
|
</Field>
|
||||||
|
</Cell>
|
||||||
|
</Block>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="my-2">
|
||||||
|
<h1 class="font-semibold">Pemeriksaan Badan</h1>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="my-2 rounded-md border border-slate-300 p-4">
|
||||||
|
<Block>
|
||||||
|
<Cell>
|
||||||
|
<Label dynamic>Kulit</Label>
|
||||||
|
<Field>
|
||||||
|
<Input />
|
||||||
|
</Field>
|
||||||
|
</Cell>
|
||||||
|
</Block>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="my-2 rounded-md border border-slate-300 p-4">
|
||||||
|
<Block :colCount="3">
|
||||||
|
<Cell>
|
||||||
|
<Label dynamic>Kepala</Label>
|
||||||
|
<Field>
|
||||||
|
<Input />
|
||||||
|
</Field>
|
||||||
|
</Cell>
|
||||||
|
<Cell>
|
||||||
|
<Label dynamic>Telinga</Label>
|
||||||
|
<Field>
|
||||||
|
<Input />
|
||||||
|
</Field>
|
||||||
|
</Cell>
|
||||||
|
<Cell>
|
||||||
|
<Label dynamic>Hidung</Label>
|
||||||
|
<Field>
|
||||||
|
<Input />
|
||||||
|
</Field>
|
||||||
|
</Cell>
|
||||||
|
</Block>
|
||||||
|
|
||||||
|
<Block :colCount="3">
|
||||||
|
<Cell>
|
||||||
|
<Label dynamic>Rongga Mulut/Tenggorokan</Label>
|
||||||
|
<Field>
|
||||||
|
<Input />
|
||||||
|
</Field>
|
||||||
|
</Cell>
|
||||||
|
<Cell>
|
||||||
|
<Label dynamic>Mata</Label>
|
||||||
|
<Field>
|
||||||
|
<Input />
|
||||||
|
</Field>
|
||||||
|
</Cell>
|
||||||
|
<Cell>
|
||||||
|
<Label dynamic>Lain-Lain</Label>
|
||||||
|
<Field>
|
||||||
|
<Input />
|
||||||
|
</Field>
|
||||||
|
</Cell>
|
||||||
|
</Block>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="my-2 rounded-md border border-slate-300 p-4">
|
||||||
|
<Block :colCount="3">
|
||||||
|
<Cell>
|
||||||
|
<Label dynamic>Leher</Label>
|
||||||
|
<Field>
|
||||||
|
<Input />
|
||||||
|
</Field>
|
||||||
|
</Cell>
|
||||||
|
<Cell>
|
||||||
|
<Label dynamic>Kelenjar Tiroid</Label>
|
||||||
|
<Field>
|
||||||
|
<Input />
|
||||||
|
</Field>
|
||||||
|
</Cell>
|
||||||
|
<Cell>
|
||||||
|
<Label dynamic>Lain-Lain</Label>
|
||||||
|
<Field>
|
||||||
|
<Input />
|
||||||
|
</Field>
|
||||||
|
</Cell>
|
||||||
|
</Block>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="my-2 rounded-md border border-slate-300 p-4">
|
||||||
|
<Block :colCount="3">
|
||||||
|
<Cell>
|
||||||
|
<Label dynamic>Thorax</Label>
|
||||||
|
<Field>
|
||||||
|
<Input />
|
||||||
|
</Field>
|
||||||
|
</Cell>
|
||||||
|
<Cell>
|
||||||
|
<Label dynamic>Jantung</Label>
|
||||||
|
<Field>
|
||||||
|
<Input />
|
||||||
|
</Field>
|
||||||
|
</Cell>
|
||||||
|
<Cell>
|
||||||
|
<Label dynamic>Paru-Paru</Label>
|
||||||
|
<Field>
|
||||||
|
<Input />
|
||||||
|
</Field>
|
||||||
|
</Cell>
|
||||||
|
</Block>
|
||||||
|
<Block>
|
||||||
|
<Cell>
|
||||||
|
<Label dynamic>Lain-Lain</Label>
|
||||||
|
<Field>
|
||||||
|
<Input />
|
||||||
|
</Field>
|
||||||
|
</Cell>
|
||||||
|
</Block>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="my-2 rounded-md border border-slate-300 p-4">
|
||||||
|
<Block :colCount="3">
|
||||||
|
<Cell>
|
||||||
|
<Label dynamic>Abdomen</Label>
|
||||||
|
<Field>
|
||||||
|
<Input />
|
||||||
|
</Field>
|
||||||
|
</Cell>
|
||||||
|
<Cell>
|
||||||
|
<Label dynamic>Hati</Label>
|
||||||
|
<Field>
|
||||||
|
<Input />
|
||||||
|
</Field>
|
||||||
|
</Cell>
|
||||||
|
<Cell>
|
||||||
|
<Label dynamic>Lien</Label>
|
||||||
|
<Field>
|
||||||
|
<Input />
|
||||||
|
</Field>
|
||||||
|
</Cell>
|
||||||
|
</Block>
|
||||||
|
<Block>
|
||||||
|
<Cell>
|
||||||
|
<Label dynamic>Lain-Lain</Label>
|
||||||
|
<Field>
|
||||||
|
<Input />
|
||||||
|
</Field>
|
||||||
|
</Cell>
|
||||||
|
</Block>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="my-2 rounded-md border border-slate-300 p-4">
|
||||||
|
<Block :colCount="3">
|
||||||
|
<Cell>
|
||||||
|
<Label dynamic>Punggung</Label>
|
||||||
|
<Field>
|
||||||
|
<Input />
|
||||||
|
</Field>
|
||||||
|
</Cell>
|
||||||
|
<Cell>
|
||||||
|
<Label dynamic>Ekstremitas</Label>
|
||||||
|
<Field>
|
||||||
|
<Input />
|
||||||
|
</Field>
|
||||||
|
</Cell>
|
||||||
|
<Cell>
|
||||||
|
<Label dynamic>Kelamin</Label>
|
||||||
|
<Field>
|
||||||
|
<Input />
|
||||||
|
</Field>
|
||||||
|
</Cell>
|
||||||
|
</Block>
|
||||||
|
<Block :colCount="2">
|
||||||
|
<Cell>
|
||||||
|
<Label dynamic>Rectum</Label>
|
||||||
|
<Field>
|
||||||
|
<Input />
|
||||||
|
</Field>
|
||||||
|
</Cell>
|
||||||
|
<Cell>
|
||||||
|
<Label dynamic>System Syaraf</Label>
|
||||||
|
<Field>
|
||||||
|
<Input />
|
||||||
|
</Field>
|
||||||
|
</Cell>
|
||||||
|
</Block>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<Block :colCount="2">
|
||||||
|
<Cell>
|
||||||
|
<Label dynamic>Neuromoskuloskeletal</Label>
|
||||||
|
<Field>
|
||||||
|
<Textarea />
|
||||||
|
</Field>
|
||||||
|
</Cell>
|
||||||
|
<Cell>
|
||||||
|
<Label dynamic>Kardiorespirasi</Label>
|
||||||
|
<Field>
|
||||||
|
<Textarea />
|
||||||
|
</Field>
|
||||||
|
</Cell>
|
||||||
|
</Block>
|
||||||
|
|
||||||
|
<Separator class="mt-8" />
|
||||||
|
|
||||||
|
<div class="my-2">
|
||||||
|
<h1 class="font-semibold">Pemeriksaan Penunjang</h1>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<Block :colCount="2">
|
||||||
|
<Cell>
|
||||||
|
<Label dynamic>Pencitraan</Label>
|
||||||
|
<Field>
|
||||||
|
<Textarea />
|
||||||
|
</Field>
|
||||||
|
</Cell>
|
||||||
|
<Cell>
|
||||||
|
<Label dynamic>Laboratorium</Label>
|
||||||
|
<Field>
|
||||||
|
<Textarea />
|
||||||
|
</Field>
|
||||||
|
</Cell>
|
||||||
|
</Block>
|
||||||
|
|
||||||
|
<div class="mb-8 grid grid-cols-2 gap-4">
|
||||||
|
<div>
|
||||||
|
<span class="text-md">Diagnosa Medis (ICD-X)</span>
|
||||||
|
<Button
|
||||||
|
class="my-2 rounded bg-orange-100 px-3 py-1 text-orange-600"
|
||||||
|
type="button"
|
||||||
|
@click="emits('click', 'prosedur')"
|
||||||
|
>
|
||||||
|
+ Pilih Prosedur
|
||||||
|
</Button>
|
||||||
|
<AppIcdPreview />
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<span class="text-md">Diagnosa Medis (ICD-X)</span>
|
||||||
|
<Button
|
||||||
|
class="my-2 rounded bg-orange-100 px-3 py-1 text-orange-600"
|
||||||
|
type="button"
|
||||||
|
@click="emits('click', 'prosedur')"
|
||||||
|
>
|
||||||
|
+ Pilih Prosedur
|
||||||
|
</Button>
|
||||||
|
<AppIcdPreview />
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<span class="text-md">Diagnosa Medis (ICD-X)</span>
|
||||||
|
<Button
|
||||||
|
class="my-2 rounded bg-orange-100 px-3 py-1 text-orange-600"
|
||||||
|
type="button"
|
||||||
|
@click="emits('click', 'prosedur')"
|
||||||
|
>
|
||||||
|
+ Pilih Prosedur
|
||||||
|
</Button>
|
||||||
|
<AppIcdPreview />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="space-y-8">
|
||||||
|
<div>
|
||||||
|
<h3 class="mb-3 text-lg font-semibold">Gangguan Fungsi</h3>
|
||||||
|
<div class="grid grid-cols-3 gap-2">
|
||||||
|
<div
|
||||||
|
v-for="opt in disorderOptions"
|
||||||
|
:key="opt"
|
||||||
|
class="flex items-center space-x-2"
|
||||||
|
>
|
||||||
|
<Checkbox
|
||||||
|
:id="opt"
|
||||||
|
:value="opt"
|
||||||
|
v-model="disorders"
|
||||||
|
/>
|
||||||
|
<Label
|
||||||
|
:for="opt"
|
||||||
|
class="text-sm"
|
||||||
|
>
|
||||||
|
{{ opt }}
|
||||||
|
</Label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="mt-4 space-y-2">
|
||||||
|
<Label
|
||||||
|
for="summary"
|
||||||
|
class="font-medium"
|
||||||
|
>
|
||||||
|
Kesimpulan Didapatkan Gangguan Fungsi
|
||||||
|
<span class="text-red-500">*</span>
|
||||||
|
</Label>
|
||||||
|
<Textarea
|
||||||
|
id="summary"
|
||||||
|
v-model="summary"
|
||||||
|
placeholder="Masukkan kesimpulan gangguan fungsi"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<Separator />
|
||||||
|
|
||||||
|
<!-- REKOMENDASI TERAPI -->
|
||||||
|
<div>
|
||||||
|
<h3 class="mb-3 text-lg font-semibold">Rekomendasi Terapi Tindakan Yang Diperlukan</h3>
|
||||||
|
<div class="grid grid-cols-3 gap-2">
|
||||||
|
<div
|
||||||
|
v-for="opt in therapyOptions"
|
||||||
|
:key="opt"
|
||||||
|
class="flex items-center space-x-2"
|
||||||
|
>
|
||||||
|
<Checkbox
|
||||||
|
:id="opt"
|
||||||
|
:value="opt"
|
||||||
|
v-model="therapies"
|
||||||
|
/>
|
||||||
|
<Label
|
||||||
|
:for="opt"
|
||||||
|
class="text-sm"
|
||||||
|
>
|
||||||
|
{{ opt }}
|
||||||
|
</Label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
import type { FormErrors } from '~/types/error'
|
import type { FormErrors } from '~/types/error'
|
||||||
import { toTypedSchema } from '@vee-validate/zod'
|
import { toTypedSchema } from '@vee-validate/zod'
|
||||||
import Block from '~/components/pub/my-ui/form/block.vue'
|
import Block from '~/components/pub/my-ui/form/block.vue'
|
||||||
import Combobox from '~/components/pub/my-ui/form/combobox.vue'
|
import Combobox from '~/components/pub/my-ui/combobox/combobox.vue'
|
||||||
import FieldGroup from '~/components/pub/my-ui/form/field-group.vue'
|
import FieldGroup from '~/components/pub/my-ui/form/field-group.vue'
|
||||||
import Field from '~/components/pub/my-ui/form/field.vue'
|
import Field from '~/components/pub/my-ui/form/field.vue'
|
||||||
import Label from '~/components/pub/my-ui/form/label.vue'
|
import Label from '~/components/pub/my-ui/form/label.vue'
|
||||||
|
|||||||
@@ -4,15 +4,16 @@ import Block from '~/components/pub/my-ui/doc-entry/block.vue'
|
|||||||
import Cell from '~/components/pub/my-ui/doc-entry/cell.vue'
|
import Cell from '~/components/pub/my-ui/doc-entry/cell.vue'
|
||||||
import Field from '~/components/pub/my-ui/doc-entry/field.vue'
|
import Field from '~/components/pub/my-ui/doc-entry/field.vue'
|
||||||
import Label from '~/components/pub/my-ui/doc-entry/label.vue'
|
import Label from '~/components/pub/my-ui/doc-entry/label.vue'
|
||||||
import Combobox from '~/components/pub/my-ui/form/combobox.vue'
|
import Combobox from '~/components/pub/my-ui/combobox/combobox.vue'
|
||||||
|
|
||||||
// Types
|
// Types
|
||||||
import type { SpecialistFormData } from '~/schemas/specialist.schema.ts'
|
import type { SpecialistFormData } from '~/schemas/specialist.schema'
|
||||||
|
|
||||||
// Helpers
|
// Helpers
|
||||||
import type z from 'zod'
|
import type z from 'zod'
|
||||||
import { toTypedSchema } from '@vee-validate/zod'
|
import { toTypedSchema } from '@vee-validate/zod'
|
||||||
import { useForm } from 'vee-validate'
|
import { useForm } from 'vee-validate'
|
||||||
|
import { genBase } from '~/models/_base'
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
schema: z.ZodSchema<any>
|
schema: z.ZodSchema<any>
|
||||||
@@ -59,6 +60,7 @@ const resetForm = () => {
|
|||||||
// Form submission handler
|
// Form submission handler
|
||||||
function onSubmitForm(values: any) {
|
function onSubmitForm(values: any) {
|
||||||
const formData: SpecialistFormData = {
|
const formData: SpecialistFormData = {
|
||||||
|
...genBase(),
|
||||||
name: name.value || '',
|
name: name.value || '',
|
||||||
code: code.value || '',
|
code: code.value || '',
|
||||||
unit_id: unit.value ? Number(unit.value) : null,
|
unit_id: unit.value ? Number(unit.value) : null,
|
||||||
|
|||||||
@@ -4,15 +4,16 @@ import Block from '~/components/pub/my-ui/doc-entry/block.vue'
|
|||||||
import Cell from '~/components/pub/my-ui/doc-entry/cell.vue'
|
import Cell from '~/components/pub/my-ui/doc-entry/cell.vue'
|
||||||
import Field from '~/components/pub/my-ui/doc-entry/field.vue'
|
import Field from '~/components/pub/my-ui/doc-entry/field.vue'
|
||||||
import Label from '~/components/pub/my-ui/doc-entry/label.vue'
|
import Label from '~/components/pub/my-ui/doc-entry/label.vue'
|
||||||
import Combobox from '~/components/pub/my-ui/form/combobox.vue'
|
import Combobox from '~/components/pub/my-ui/combobox/combobox.vue'
|
||||||
|
|
||||||
// Types
|
// Types
|
||||||
import type { SubspecialistFormData } from '~/schemas/subspecialist.schema.ts'
|
import type { SubspecialistFormData } from '~/schemas/subspecialist.schema'
|
||||||
|
|
||||||
// Helpers
|
// Helpers
|
||||||
import type z from 'zod'
|
import type z from 'zod'
|
||||||
import { toTypedSchema } from '@vee-validate/zod'
|
import { toTypedSchema } from '@vee-validate/zod'
|
||||||
import { useForm } from 'vee-validate'
|
import { useForm } from 'vee-validate'
|
||||||
|
import { genBase } from '~/models/_base'
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
schema: z.ZodSchema<any>
|
schema: z.ZodSchema<any>
|
||||||
@@ -60,6 +61,7 @@ const resetForm = () => {
|
|||||||
// Form submission handler
|
// Form submission handler
|
||||||
function onSubmitForm(values: any) {
|
function onSubmitForm(values: any) {
|
||||||
const formData: SubspecialistFormData = {
|
const formData: SubspecialistFormData = {
|
||||||
|
...genBase(),
|
||||||
name: name.value || '',
|
name: name.value || '',
|
||||||
code: code.value || '',
|
code: code.value || '',
|
||||||
specialist_id: specialist.value ? Number(specialist.value) : null,
|
specialist_id: specialist.value ? Number(specialist.value) : null,
|
||||||
|
|||||||
@@ -6,12 +6,13 @@ import Field from '~/components/pub/my-ui/doc-entry/field.vue'
|
|||||||
import Label from '~/components/pub/my-ui/doc-entry/label.vue'
|
import Label from '~/components/pub/my-ui/doc-entry/label.vue'
|
||||||
|
|
||||||
// Types
|
// Types
|
||||||
import type { DeviceFormData } from '~/schemas/device.schema.ts'
|
import type { DeviceFormData } from '~/schemas/device.schema'
|
||||||
|
|
||||||
// Helpers
|
// Helpers
|
||||||
import type z from 'zod'
|
import type z from 'zod'
|
||||||
import { toTypedSchema } from '@vee-validate/zod'
|
import { toTypedSchema } from '@vee-validate/zod'
|
||||||
import { useForm } from 'vee-validate'
|
import { useForm } from 'vee-validate'
|
||||||
|
import { genBase } from '~/models/_base'
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
schema: z.ZodSchema<any>
|
schema: z.ZodSchema<any>
|
||||||
@@ -59,6 +60,7 @@ const resetForm = () => {
|
|||||||
// Form submission handler
|
// Form submission handler
|
||||||
function onSubmitForm(values: any) {
|
function onSubmitForm(values: any) {
|
||||||
const formData: DeviceFormData = {
|
const formData: DeviceFormData = {
|
||||||
|
...genBase(),
|
||||||
name: name.value || '',
|
name: name.value || '',
|
||||||
code: code.value || '',
|
code: code.value || '',
|
||||||
uom_code: uom.value || '',
|
uom_code: uom.value || '',
|
||||||
@@ -73,18 +75,35 @@ function onCancelForm() {
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<form id="form-tools" @submit.prevent>
|
<form
|
||||||
<Block labelSize="thin" class="!mb-2.5 !pt-0 xl:!mb-3" :colCount="1">
|
id="form-tools"
|
||||||
|
@submit.prevent
|
||||||
|
>
|
||||||
|
<Block
|
||||||
|
labelSize="thin"
|
||||||
|
class="!mb-2.5 !pt-0 xl:!mb-3"
|
||||||
|
:colCount="1"
|
||||||
|
>
|
||||||
<Cell>
|
<Cell>
|
||||||
<Label height="compact">Kode</Label>
|
<Label height="compact">Kode</Label>
|
||||||
<Field :errMessage="errors.code">
|
<Field :errMessage="errors.code">
|
||||||
<Input id="code" v-model="code" v-bind="codeAttrs" :disabled="isLoading || isReadonly" />
|
<Input
|
||||||
|
id="code"
|
||||||
|
v-model="code"
|
||||||
|
v-bind="codeAttrs"
|
||||||
|
:disabled="isLoading || isReadonly"
|
||||||
|
/>
|
||||||
</Field>
|
</Field>
|
||||||
</Cell>
|
</Cell>
|
||||||
<Cell>
|
<Cell>
|
||||||
<Label height="compact">Nama</Label>
|
<Label height="compact">Nama</Label>
|
||||||
<Field :errMessage="errors.name">
|
<Field :errMessage="errors.name">
|
||||||
<Input id="name" v-model="name" v-bind="nameAttrs" :disabled="isLoading || isReadonly" />
|
<Input
|
||||||
|
id="name"
|
||||||
|
v-model="name"
|
||||||
|
v-bind="nameAttrs"
|
||||||
|
:disabled="isLoading || isReadonly"
|
||||||
|
/>
|
||||||
</Field>
|
</Field>
|
||||||
</Cell>
|
</Cell>
|
||||||
<Cell>
|
<Cell>
|
||||||
@@ -103,7 +122,14 @@ function onCancelForm() {
|
|||||||
</Cell>
|
</Cell>
|
||||||
</Block>
|
</Block>
|
||||||
<div class="my-2 flex justify-end gap-2 py-2">
|
<div class="my-2 flex justify-end gap-2 py-2">
|
||||||
<Button type="button" variant="secondary" class="w-[120px]" @click="onCancelForm"> Kembali </Button>
|
<Button
|
||||||
|
type="button"
|
||||||
|
variant="secondary"
|
||||||
|
class="w-[120px]"
|
||||||
|
@click="onCancelForm"
|
||||||
|
>
|
||||||
|
Kembali
|
||||||
|
</Button>
|
||||||
<Button
|
<Button
|
||||||
v-if="!isReadonly"
|
v-if="!isReadonly"
|
||||||
type="button"
|
type="button"
|
||||||
|
|||||||
@@ -4,10 +4,10 @@ import Block from '~/components/pub/my-ui/doc-entry/block.vue'
|
|||||||
import Cell from '~/components/pub/my-ui/doc-entry/cell.vue'
|
import Cell from '~/components/pub/my-ui/doc-entry/cell.vue'
|
||||||
import Field from '~/components/pub/my-ui/doc-entry/field.vue'
|
import Field from '~/components/pub/my-ui/doc-entry/field.vue'
|
||||||
import Label from '~/components/pub/my-ui/doc-entry/label.vue'
|
import Label from '~/components/pub/my-ui/doc-entry/label.vue'
|
||||||
import Combobox from '~/components/pub/my-ui/form/combobox.vue'
|
import Combobox from '~/components/pub/my-ui/combobox/combobox.vue'
|
||||||
|
|
||||||
// Types
|
// Types
|
||||||
import type { UnitFormData } from '~/schemas/unit.schema.ts'
|
import type { UnitFormData } from '~/schemas/unit.schema'
|
||||||
|
|
||||||
// Helpers
|
// Helpers
|
||||||
import type z from 'zod'
|
import type z from 'zod'
|
||||||
@@ -48,7 +48,7 @@ if (props.values) {
|
|||||||
if (props.values.code !== undefined) code.value = props.values.code
|
if (props.values.code !== undefined) code.value = props.values.code
|
||||||
if (props.values.name !== undefined) name.value = props.values.name
|
if (props.values.name !== undefined) name.value = props.values.name
|
||||||
if (props.values.installation_id !== undefined)
|
if (props.values.installation_id !== undefined)
|
||||||
installation.value = props.values.installation_id ? String(props.values.installation_id) : null
|
installation.value = props.values.installation_id ? Number(props.values.installation_id) : null
|
||||||
}
|
}
|
||||||
|
|
||||||
const resetForm = () => {
|
const resetForm = () => {
|
||||||
@@ -58,7 +58,7 @@ const resetForm = () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Form submission handler
|
// Form submission handler
|
||||||
function onSubmitForm(values: any) {
|
function onSubmitForm() {
|
||||||
const formData: UnitFormData = {
|
const formData: UnitFormData = {
|
||||||
name: name.value || '',
|
name: name.value || '',
|
||||||
code: code.value || '',
|
code: code.value || '',
|
||||||
@@ -74,18 +74,35 @@ function onCancelForm() {
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<form id="form-unit" @submit.prevent>
|
<form
|
||||||
<Block labelSize="thin" class="!mb-2.5 !pt-0 xl:!mb-3" :colCount="1">
|
id="form-unit"
|
||||||
|
@submit.prevent
|
||||||
|
>
|
||||||
|
<Block
|
||||||
|
labelSize="thin"
|
||||||
|
class="!mb-2.5 !pt-0 xl:!mb-3"
|
||||||
|
:colCount="1"
|
||||||
|
>
|
||||||
<Cell>
|
<Cell>
|
||||||
<Label height="compact">Kode</Label>
|
<Label height="compact">Kode</Label>
|
||||||
<Field :errMessage="errors.code">
|
<Field :errMessage="errors.code">
|
||||||
<Input id="code" v-model="code" v-bind="codeAttrs" :disabled="isLoading || isReadonly" />
|
<Input
|
||||||
|
id="code"
|
||||||
|
v-model="code"
|
||||||
|
v-bind="codeAttrs"
|
||||||
|
:disabled="isLoading || isReadonly"
|
||||||
|
/>
|
||||||
</Field>
|
</Field>
|
||||||
</Cell>
|
</Cell>
|
||||||
<Cell>
|
<Cell>
|
||||||
<Label height="compact">Nama</Label>
|
<Label height="compact">Nama</Label>
|
||||||
<Field :errMessage="errors.name">
|
<Field :errMessage="errors.name">
|
||||||
<Input id="name" v-model="name" v-bind="nameAttrs" :disabled="isLoading || isReadonly" />
|
<Input
|
||||||
|
id="name"
|
||||||
|
v-model="name"
|
||||||
|
v-bind="nameAttrs"
|
||||||
|
:disabled="isLoading || isReadonly"
|
||||||
|
/>
|
||||||
</Field>
|
</Field>
|
||||||
</Cell>
|
</Cell>
|
||||||
<Cell>
|
<Cell>
|
||||||
@@ -105,7 +122,14 @@ function onCancelForm() {
|
|||||||
</Cell>
|
</Cell>
|
||||||
</Block>
|
</Block>
|
||||||
<div class="my-2 flex justify-end gap-2 py-2">
|
<div class="my-2 flex justify-end gap-2 py-2">
|
||||||
<Button type="button" variant="secondary" class="w-[120px]" @click="onCancelForm"> Kembali </Button>
|
<Button
|
||||||
|
type="button"
|
||||||
|
variant="secondary"
|
||||||
|
class="w-[120px]"
|
||||||
|
@click="onCancelForm"
|
||||||
|
>
|
||||||
|
Kembali
|
||||||
|
</Button>
|
||||||
<Button
|
<Button
|
||||||
v-if="!isReadonly"
|
v-if="!isReadonly"
|
||||||
type="button"
|
type="button"
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
// Components
|
// Components
|
||||||
import Block from '~/components/pub/my-ui/doc-entry/block.vue'
|
import Block from '~/components/pub/my-ui/doc-entry/block.vue'
|
||||||
@@ -8,7 +7,7 @@ import Label from '~/components/pub/my-ui/doc-entry/label.vue'
|
|||||||
import Button from '~/components/pub/ui/button/Button.vue'
|
import Button from '~/components/pub/ui/button/Button.vue'
|
||||||
|
|
||||||
// Types
|
// Types
|
||||||
import type { UomFormData } from '~/schemas/uom.schema.ts'
|
import type { UomFormData } from '~/schemas/uom.schema'
|
||||||
|
|
||||||
// Helpers
|
// Helpers
|
||||||
import type z from 'zod'
|
import type z from 'zod'
|
||||||
@@ -65,23 +64,47 @@ function onCancelForm() {
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<form id="form-medicine-method" @submit.prevent>
|
<form
|
||||||
<Block labelSize="thin" class="!mb-2.5 !pt-0 xl:!mb-3" :colCount="1">
|
id="form-medicine-method"
|
||||||
|
@submit.prevent
|
||||||
|
>
|
||||||
|
<Block
|
||||||
|
labelSize="thin"
|
||||||
|
class="!mb-2.5 !pt-0 xl:!mb-3"
|
||||||
|
:colCount="1"
|
||||||
|
>
|
||||||
<Cell>
|
<Cell>
|
||||||
<Label height="">Kode</Label>
|
<Label height="">Kode</Label>
|
||||||
<Field :errMessage="errors.code">
|
<Field :errMessage="errors.code">
|
||||||
<Input id="code" v-model="code" v-bind="codeAttrs" :disabled="isLoading || isReadonly" />
|
<Input
|
||||||
|
id="code"
|
||||||
|
v-model="code"
|
||||||
|
v-bind="codeAttrs"
|
||||||
|
:disabled="isLoading || isReadonly"
|
||||||
|
/>
|
||||||
</Field>
|
</Field>
|
||||||
</Cell>
|
</Cell>
|
||||||
<Cell>
|
<Cell>
|
||||||
<Label height="compact">Nama</Label>
|
<Label height="compact">Nama</Label>
|
||||||
<Field :errMessage="errors.name">
|
<Field :errMessage="errors.name">
|
||||||
<Input id="name" v-model="name" v-bind="nameAttrs" :disabled="isLoading || isReadonly" />
|
<Input
|
||||||
|
id="name"
|
||||||
|
v-model="name"
|
||||||
|
v-bind="nameAttrs"
|
||||||
|
:disabled="isLoading || isReadonly"
|
||||||
|
/>
|
||||||
</Field>
|
</Field>
|
||||||
</Cell>
|
</Cell>
|
||||||
</Block>
|
</Block>
|
||||||
<div class="my-2 flex justify-end gap-2 py-2">
|
<div class="my-2 flex justify-end gap-2 py-2">
|
||||||
<Button type="button" variant="secondary" class="w-[120px]" @click="onCancelForm"> Kembali </Button>
|
<Button
|
||||||
|
type="button"
|
||||||
|
variant="secondary"
|
||||||
|
class="w-[120px]"
|
||||||
|
@click="onCancelForm"
|
||||||
|
>
|
||||||
|
Kembali
|
||||||
|
</Button>
|
||||||
<Button
|
<Button
|
||||||
v-if="!isReadonly"
|
v-if="!isReadonly"
|
||||||
type="button"
|
type="button"
|
||||||
|
|||||||
@@ -5,6 +5,10 @@ import Cell from '~/components/pub/my-ui/doc-entry/cell.vue'
|
|||||||
import Field from '~/components/pub/my-ui/doc-entry/field.vue'
|
import Field from '~/components/pub/my-ui/doc-entry/field.vue'
|
||||||
import Label from '~/components/pub/my-ui/doc-entry/label.vue'
|
import Label from '~/components/pub/my-ui/doc-entry/label.vue'
|
||||||
import Button from '~/components/pub/ui/button/Button.vue'
|
import Button from '~/components/pub/ui/button/Button.vue'
|
||||||
|
import Combobox from '~/components/pub/my-ui/combobox/combobox.vue'
|
||||||
|
|
||||||
|
// Constants
|
||||||
|
import { infraGroupCodesKeys } from '~/lib/constants'
|
||||||
|
|
||||||
// Types
|
// Types
|
||||||
import type { InfraFormData } from '~/schemas/infra.schema'
|
import type { InfraFormData } from '~/schemas/infra.schema'
|
||||||
@@ -16,6 +20,7 @@ import { toTypedSchema } from '@vee-validate/zod'
|
|||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
schema: z.ZodSchema<any>
|
schema: z.ZodSchema<any>
|
||||||
|
parents: any[]
|
||||||
values: any
|
values: any
|
||||||
isLoading?: boolean
|
isLoading?: boolean
|
||||||
isReadonly?: boolean
|
isReadonly?: boolean
|
||||||
@@ -34,27 +39,28 @@ const { defineField, errors, meta } = useForm({
|
|||||||
initialValues: {
|
initialValues: {
|
||||||
code: '',
|
code: '',
|
||||||
name: '',
|
name: '',
|
||||||
infraGroup_code: 'counter',
|
infraGroup_code: infraGroupCodesKeys.warehouse,
|
||||||
parent_id: null,
|
parent_id: null,
|
||||||
} as Partial<InfraFormData>,
|
} as Partial<InfraFormData>,
|
||||||
})
|
})
|
||||||
|
|
||||||
const [code, codeAttrs] = defineField('code')
|
const [code, codeAttrs] = defineField('code')
|
||||||
const [name, nameAttrs] = defineField('name')
|
const [name, nameAttrs] = defineField('name')
|
||||||
const [infraGroup_code, infraGroupAttrs] = defineField('infraGroup_code')
|
const [infraGroup_code] = defineField('infraGroup_code')
|
||||||
const [parent_id, parentIdAttrs] = defineField('parent_id')
|
const [parent_id, parentIdAttrs] = defineField('parent_id')
|
||||||
|
|
||||||
if (props.values) {
|
if (props.values) {
|
||||||
if (props.values.code !== undefined) code.value = props.values.code
|
if (props.values.code !== undefined) code.value = props.values.code
|
||||||
if (props.values.name !== undefined) name.value = props.values.name
|
if (props.values.name !== undefined) name.value = props.values.name
|
||||||
if (props.values.infraGroup_code !== undefined) infraGroup_code.value = props.values.infraGroup_code
|
if (props.values.infraGroup_code !== undefined) infraGroup_code.value = props.values.infraGroup_code
|
||||||
if (props.values.parent_id !== undefined) parent_id.value = props.values.parent_id
|
if (props.values.parent_id !== undefined)
|
||||||
|
parent_id.value = props.values.parent_id ? Number(props.values.parent_id) : null
|
||||||
}
|
}
|
||||||
|
|
||||||
const resetForm = () => {
|
const resetForm = () => {
|
||||||
code.value = ''
|
code.value = ''
|
||||||
name.value = ''
|
name.value = ''
|
||||||
infraGroup_code.value = 'counter'
|
infraGroup_code.value = infraGroupCodesKeys.warehouse
|
||||||
parent_id.value = null
|
parent_id.value = null
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -62,8 +68,8 @@ function onSubmitForm() {
|
|||||||
const formData: InfraFormData = {
|
const formData: InfraFormData = {
|
||||||
code: code.value || '',
|
code: code.value || '',
|
||||||
name: name.value || '',
|
name: name.value || '',
|
||||||
infraGroup_code: infraGroup_code.value || 'counter',
|
infraGroup_code: infraGroup_code.value || infraGroupCodesKeys.warehouse,
|
||||||
parent_id: parent_id.value || null,
|
parent_id: parent_id.value ? Number(parent_id.value) : null,
|
||||||
}
|
}
|
||||||
emit('submit', formData, resetForm)
|
emit('submit', formData, resetForm)
|
||||||
}
|
}
|
||||||
@@ -74,23 +80,62 @@ function onCancelForm() {
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<form id="form-counter" @submit.prevent>
|
<form
|
||||||
<Block labelSize="thin" class="!mb-2.5 !pt-0 xl:!mb-3" :colCount="1">
|
id="form-floor"
|
||||||
|
@submit.prevent
|
||||||
|
>
|
||||||
|
<Block
|
||||||
|
labelSize="thin"
|
||||||
|
class="!mb-2.5 !pt-0 xl:!mb-3"
|
||||||
|
:colCount="1"
|
||||||
|
>
|
||||||
<Cell>
|
<Cell>
|
||||||
<Label height="compact">Kode</Label>
|
<Label height="compact">Kode</Label>
|
||||||
<Field :errMessage="errors.code">
|
<Field :errMessage="errors.code">
|
||||||
<Input id="code" v-model="code" v-bind="codeAttrs" :disabled="isLoading || isReadonly" />
|
<Input
|
||||||
|
id="code"
|
||||||
|
v-model="code"
|
||||||
|
v-bind="codeAttrs"
|
||||||
|
:disabled="isLoading || isReadonly"
|
||||||
|
/>
|
||||||
</Field>
|
</Field>
|
||||||
</Cell>
|
</Cell>
|
||||||
<Cell>
|
<Cell>
|
||||||
<Label height="compact">Nama</Label>
|
<Label height="compact">Nama</Label>
|
||||||
<Field :errMessage="errors.name">
|
<Field :errMessage="errors.name">
|
||||||
<Input id="name" v-model="name" v-bind="nameAttrs" :disabled="isLoading || isReadonly" />
|
<Input
|
||||||
|
id="name"
|
||||||
|
v-model="name"
|
||||||
|
v-bind="nameAttrs"
|
||||||
|
:disabled="isLoading || isReadonly"
|
||||||
|
/>
|
||||||
|
</Field>
|
||||||
|
</Cell>
|
||||||
|
<Cell>
|
||||||
|
<Label height="compact">Lantai</Label>
|
||||||
|
<Field :errMessage="errors.parent_id">
|
||||||
|
<Combobox
|
||||||
|
id="parent"
|
||||||
|
v-model="parent_id"
|
||||||
|
v-bind="parentIdAttrs"
|
||||||
|
:items="parents"
|
||||||
|
:is-disabled="isLoading || isReadonly"
|
||||||
|
placeholder="Pilih Lantai"
|
||||||
|
search-placeholder="Cari Lantai"
|
||||||
|
empty-message="Item tidak ditemukan"
|
||||||
|
/>
|
||||||
</Field>
|
</Field>
|
||||||
</Cell>
|
</Cell>
|
||||||
</Block>
|
</Block>
|
||||||
<div class="my-2 flex justify-end gap-2 py-2">
|
<div class="my-2 flex justify-end gap-2 py-2">
|
||||||
<Button type="button" variant="secondary" class="w-[120px]" @click="onCancelForm"> Kembali </Button>
|
<Button
|
||||||
|
type="button"
|
||||||
|
variant="secondary"
|
||||||
|
class="w-[120px]"
|
||||||
|
@click="onCancelForm"
|
||||||
|
>
|
||||||
|
Kembali
|
||||||
|
</Button>
|
||||||
<Button
|
<Button
|
||||||
v-if="!isReadonly"
|
v-if="!isReadonly"
|
||||||
type="button"
|
type="button"
|
||||||
|
|||||||
@@ -12,9 +12,9 @@ type SmallDetailDto = any
|
|||||||
|
|
||||||
const action = defineAsyncComponent(() => import('~/components/pub/my-ui/data/dropdown-action-dud.vue'))
|
const action = defineAsyncComponent(() => import('~/components/pub/my-ui/data/dropdown-action-dud.vue'))
|
||||||
|
|
||||||
export const cols: Col[] = [{ width: 100 }, {}, {}, { width: 50 }]
|
export const cols: Col[] = [{}, {}, {}, { width: 50 }]
|
||||||
|
|
||||||
export const header: Th[][] = [[{ label: 'Kode' }, { label: 'Nama' }, { label: 'Counter Induk' }, { label: '' }]]
|
export const header: Th[][] = [[{ label: 'Kode' }, { label: 'Nama' }, { label: 'Lantai' }, { label: '' }]]
|
||||||
|
|
||||||
export const keys = ['code', 'name', 'parent', 'action']
|
export const keys = ['code', 'name', 'parent', 'action']
|
||||||
|
|
||||||
@@ -36,9 +36,6 @@ export const funcComponent: RecStrFuncComponent = {
|
|||||||
idx,
|
idx,
|
||||||
rec: rec as object,
|
rec: rec as object,
|
||||||
component: action,
|
component: action,
|
||||||
props: {
|
|
||||||
size: 'sm',
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
return res
|
return res
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1,6 +1,11 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import type { PaginationMeta } from '~/components/pub/my-ui/pagination/pagination.type'
|
// Components
|
||||||
import PaginationView from '~/components/pub/my-ui/pagination/pagination-view.vue'
|
import PaginationView from '~/components/pub/my-ui/pagination/pagination-view.vue'
|
||||||
|
|
||||||
|
// Types
|
||||||
|
import type { PaginationMeta } from '~/components/pub/my-ui/pagination/pagination.type'
|
||||||
|
|
||||||
|
// Configs
|
||||||
import { cols, funcComponent, funcHtml, funcParsed, header, keys } from './list-cfg'
|
import { cols, funcComponent, funcHtml, funcParsed, header, keys } from './list-cfg'
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
@@ -21,7 +26,7 @@ function handlePageChange(page: number) {
|
|||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="space-y-4">
|
<div class="space-y-4">
|
||||||
<PubBaseDataTable
|
<PubMyUiDataTable
|
||||||
:rows="data"
|
:rows="data"
|
||||||
:cols="cols"
|
:cols="cols"
|
||||||
:header="header"
|
:header="header"
|
||||||
|
|||||||
@@ -1,8 +1,198 @@
|
|||||||
<!-- Duplicated from content/counter/list.vue for bed -->
|
|
||||||
<!-- TODO: Update logic and fields for bed context -->
|
|
||||||
<template>
|
|
||||||
...existing code...
|
|
||||||
</template>
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
// ...existing code...
|
// Components
|
||||||
|
import Dialog from '~/components/pub/my-ui/modal/dialog.vue'
|
||||||
|
import Header from '~/components/pub/my-ui/nav-header/prep.vue'
|
||||||
|
import AppBedList from '~/components/app/bed/list.vue'
|
||||||
|
import AppBedEntryForm from '~/components/app/bed/entry-form.vue'
|
||||||
|
import RecordConfirmation from '~/components/pub/my-ui/confirmation/record-confirmation.vue'
|
||||||
|
|
||||||
|
// Constants
|
||||||
|
import { infraGroupCodesKeys } from '~/lib/constants'
|
||||||
|
|
||||||
|
// Helpers
|
||||||
|
import { usePaginatedList } from '~/composables/usePaginatedList'
|
||||||
|
import { toast } from '~/components/pub/ui/toast'
|
||||||
|
|
||||||
|
// Types
|
||||||
|
import { ActionEvents, type HeaderPrep } from '~/components/pub/my-ui/data/types'
|
||||||
|
import { InfraSchema, type InfraFormData } from '~/schemas/infra.schema'
|
||||||
|
|
||||||
|
// Handlers
|
||||||
|
import {
|
||||||
|
recId,
|
||||||
|
recAction,
|
||||||
|
recItem,
|
||||||
|
isReadonly,
|
||||||
|
isProcessing,
|
||||||
|
isFormEntryDialogOpen,
|
||||||
|
isRecordConfirmationOpen,
|
||||||
|
onResetState,
|
||||||
|
handleActionSave,
|
||||||
|
handleActionEdit,
|
||||||
|
handleActionRemove,
|
||||||
|
handleCancelForm,
|
||||||
|
} from '~/handlers/infra.handler'
|
||||||
|
|
||||||
|
// Services
|
||||||
|
import { getList, getDetail, getValueLabelList } from '~/services/infra.service'
|
||||||
|
|
||||||
|
const parents = ref<{ value: string | number; label: string }[]>([])
|
||||||
|
const title = ref('')
|
||||||
|
|
||||||
|
const {
|
||||||
|
data,
|
||||||
|
isLoading,
|
||||||
|
paginationMeta,
|
||||||
|
searchInput,
|
||||||
|
handlePageChange,
|
||||||
|
handleSearch,
|
||||||
|
fetchData: getItemList,
|
||||||
|
} = usePaginatedList({
|
||||||
|
fetchFn: async (params: any) => {
|
||||||
|
const result = await getList({
|
||||||
|
search: params.search,
|
||||||
|
sort: 'createdAt:asc',
|
||||||
|
'page-number': params['page-number'] || 2,
|
||||||
|
'page-size': params['page-size'] || 10,
|
||||||
|
'infraGroup-code': infraGroupCodesKeys.bed,
|
||||||
|
includes: 'parent',
|
||||||
|
})
|
||||||
|
return { success: result.success || false, body: result.body || {} }
|
||||||
|
},
|
||||||
|
entityName: 'bed',
|
||||||
|
})
|
||||||
|
|
||||||
|
const headerPrep: HeaderPrep = {
|
||||||
|
title: 'Kasur',
|
||||||
|
icon: 'i-lucide-layout-list',
|
||||||
|
refSearchNav: {
|
||||||
|
placeholder: 'Cari (min. 3 karakter)...',
|
||||||
|
minLength: 3,
|
||||||
|
debounceMs: 500,
|
||||||
|
showValidationFeedback: true,
|
||||||
|
onInput: (val: string) => {
|
||||||
|
searchInput.value = val
|
||||||
|
},
|
||||||
|
onClick: () => {},
|
||||||
|
onClear: () => {},
|
||||||
|
},
|
||||||
|
addNav: {
|
||||||
|
label: 'Tambah',
|
||||||
|
icon: 'i-lucide-plus',
|
||||||
|
onClick: () => {
|
||||||
|
recItem.value = null
|
||||||
|
recId.value = 0
|
||||||
|
isFormEntryDialogOpen.value = true
|
||||||
|
isReadonly.value = false
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
provide('rec_id', recId)
|
||||||
|
provide('rec_action', recAction)
|
||||||
|
provide('rec_item', recItem)
|
||||||
|
provide('table_data_loader', isLoading)
|
||||||
|
|
||||||
|
const getCurrentDetail = async (id: number | string) => {
|
||||||
|
const result = await getDetail(id)
|
||||||
|
if (result.success) {
|
||||||
|
const currentValue = result.body?.data || {}
|
||||||
|
recItem.value = currentValue
|
||||||
|
isFormEntryDialogOpen.value = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
watch([recId, recAction], () => {
|
||||||
|
switch (recAction.value) {
|
||||||
|
case ActionEvents.showDetail:
|
||||||
|
getCurrentDetail(recId.value)
|
||||||
|
title.value = 'Detail Kasur'
|
||||||
|
isReadonly.value = true
|
||||||
|
break
|
||||||
|
case ActionEvents.showEdit:
|
||||||
|
getCurrentDetail(recId.value)
|
||||||
|
title.value = 'Edit Kasur'
|
||||||
|
isReadonly.value = false
|
||||||
|
break
|
||||||
|
case ActionEvents.showConfirmDelete:
|
||||||
|
isRecordConfirmationOpen.value = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
onMounted(async () => {
|
||||||
|
parents.value = await getValueLabelList({ sort: 'createdAt:asc', 'infraGroup-code': infraGroupCodesKeys.chamber })
|
||||||
|
await getItemList()
|
||||||
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<Header
|
||||||
|
v-model="searchInput"
|
||||||
|
:prep="headerPrep"
|
||||||
|
:ref-search-nav="headerPrep.refSearchNav"
|
||||||
|
@search="handleSearch"
|
||||||
|
class="mb-4 xl:mb-5"
|
||||||
|
/>
|
||||||
|
<AppBedList
|
||||||
|
:data="data"
|
||||||
|
:pagination-meta="paginationMeta"
|
||||||
|
@page-change="handlePageChange"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<Dialog
|
||||||
|
v-model:open="isFormEntryDialogOpen"
|
||||||
|
:title="!!recItem ? title : 'Tambah Kasur'"
|
||||||
|
size="lg"
|
||||||
|
prevent-outside
|
||||||
|
@update:open="
|
||||||
|
(value: any) => {
|
||||||
|
onResetState()
|
||||||
|
isFormEntryDialogOpen = value
|
||||||
|
}
|
||||||
|
"
|
||||||
|
>
|
||||||
|
<AppBedEntryForm
|
||||||
|
:schema="InfraSchema"
|
||||||
|
:parents="parents"
|
||||||
|
:values="recItem"
|
||||||
|
:is-loading="isProcessing"
|
||||||
|
:is-readonly="isReadonly"
|
||||||
|
@submit="
|
||||||
|
(values: InfraFormData | Record<string, any>, resetForm: () => void) => {
|
||||||
|
if (recId > 0) {
|
||||||
|
handleActionEdit(recId, values, getItemList, resetForm, toast)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
handleActionSave(values, getItemList, resetForm, toast)
|
||||||
|
}
|
||||||
|
"
|
||||||
|
@cancel="handleCancelForm"
|
||||||
|
/>
|
||||||
|
</Dialog>
|
||||||
|
|
||||||
|
<RecordConfirmation
|
||||||
|
v-model:open="isRecordConfirmationOpen"
|
||||||
|
action="delete"
|
||||||
|
:record="recItem"
|
||||||
|
@confirm="() => handleActionRemove(recId, getItemList, toast)"
|
||||||
|
@cancel=""
|
||||||
|
>
|
||||||
|
<template #default="{ record }">
|
||||||
|
<div class="text-sm">
|
||||||
|
<p>
|
||||||
|
<strong>ID:</strong>
|
||||||
|
{{ record?.id }}
|
||||||
|
</p>
|
||||||
|
<p v-if="record?.name">
|
||||||
|
<strong>Nama:</strong>
|
||||||
|
{{ record.name }}
|
||||||
|
</p>
|
||||||
|
<p v-if="record?.code">
|
||||||
|
<strong>Kode:</strong>
|
||||||
|
{{ record.code }}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</RecordConfirmation>
|
||||||
|
</template>
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import AppBuildingEntryForm from '~/components/app/building/entry-form.vue'
|
|||||||
import RecordConfirmation from '~/components/pub/my-ui/confirmation/record-confirmation.vue'
|
import RecordConfirmation from '~/components/pub/my-ui/confirmation/record-confirmation.vue'
|
||||||
|
|
||||||
// Constants
|
// Constants
|
||||||
import { infraGroupCodesKeys } from "~/lib/constants"
|
import { infraGroupCodesKeys } from '~/lib/constants'
|
||||||
|
|
||||||
// Helpers
|
// Helpers
|
||||||
import { usePaginatedList } from '~/composables/usePaginatedList'
|
import { usePaginatedList } from '~/composables/usePaginatedList'
|
||||||
@@ -26,6 +26,7 @@ import {
|
|||||||
isProcessing,
|
isProcessing,
|
||||||
isFormEntryDialogOpen,
|
isFormEntryDialogOpen,
|
||||||
isRecordConfirmationOpen,
|
isRecordConfirmationOpen,
|
||||||
|
onResetState,
|
||||||
handleActionSave,
|
handleActionSave,
|
||||||
handleActionEdit,
|
handleActionEdit,
|
||||||
handleActionRemove,
|
handleActionRemove,
|
||||||
@@ -49,6 +50,7 @@ const {
|
|||||||
fetchFn: async (params: any) => {
|
fetchFn: async (params: any) => {
|
||||||
const result = await getList({
|
const result = await getList({
|
||||||
search: params.search,
|
search: params.search,
|
||||||
|
sort: 'createdAt:asc',
|
||||||
'page-number': params['page-number'] || 0,
|
'page-number': params['page-number'] || 0,
|
||||||
'page-size': params['page-size'] || 10,
|
'page-size': params['page-size'] || 10,
|
||||||
'infraGroup-code': infraGroupCodesKeys.building,
|
'infraGroup-code': infraGroupCodesKeys.building,
|
||||||
@@ -62,7 +64,7 @@ const headerPrep: HeaderPrep = {
|
|||||||
title: 'Gedung',
|
title: 'Gedung',
|
||||||
icon: 'i-lucide-layout-list',
|
icon: 'i-lucide-layout-list',
|
||||||
refSearchNav: {
|
refSearchNav: {
|
||||||
placeholder: 'Cari gedung...',
|
placeholder: 'Cari (min. 3 karakter)...',
|
||||||
minLength: 3,
|
minLength: 3,
|
||||||
debounceMs: 500,
|
debounceMs: 500,
|
||||||
showValidationFeedback: true,
|
showValidationFeedback: true,
|
||||||
@@ -122,10 +124,31 @@ onMounted(async () => {
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<Header v-model="searchInput" :prep="headerPrep" @search="handleSearch" class="mb-4 xl:mb-5" />
|
<Header
|
||||||
<AppBuildingList :data="data" :pagination-meta="paginationMeta" @page-change="handlePageChange" />
|
v-model="searchInput"
|
||||||
|
:prep="headerPrep"
|
||||||
|
:ref-search-nav="headerPrep.refSearchNav"
|
||||||
|
@search="handleSearch"
|
||||||
|
class="mb-4 xl:mb-5"
|
||||||
|
/>
|
||||||
|
<AppBuildingList
|
||||||
|
:data="data"
|
||||||
|
:pagination-meta="paginationMeta"
|
||||||
|
@page-change="handlePageChange"
|
||||||
|
/>
|
||||||
|
|
||||||
<Dialog v-model:open="isFormEntryDialogOpen" :title="!!recItem ? title : 'Tambah Gedung'" size="lg" prevent-outside>
|
<Dialog
|
||||||
|
v-model:open="isFormEntryDialogOpen"
|
||||||
|
:title="!!recItem ? title : 'Tambah Gedung'"
|
||||||
|
size="lg"
|
||||||
|
prevent-outside
|
||||||
|
@update:open="
|
||||||
|
(value: any) => {
|
||||||
|
onResetState()
|
||||||
|
isFormEntryDialogOpen = value
|
||||||
|
}
|
||||||
|
"
|
||||||
|
>
|
||||||
<AppBuildingEntryForm
|
<AppBuildingEntryForm
|
||||||
:schema="InfraSchema"
|
:schema="InfraSchema"
|
||||||
:values="recItem"
|
:values="recItem"
|
||||||
@@ -153,9 +176,18 @@ onMounted(async () => {
|
|||||||
>
|
>
|
||||||
<template #default="{ record }">
|
<template #default="{ record }">
|
||||||
<div class="text-sm">
|
<div class="text-sm">
|
||||||
<p><strong>ID:</strong> {{ record?.id }}</p>
|
<p>
|
||||||
<p v-if="record?.name"><strong>Nama:</strong> {{ record.name }}</p>
|
<strong>ID:</strong>
|
||||||
<p v-if="record?.code"><strong>Kode:</strong> {{ record.code }}</p>
|
{{ record?.id }}
|
||||||
|
</p>
|
||||||
|
<p v-if="record?.name">
|
||||||
|
<strong>Nama:</strong>
|
||||||
|
{{ record.name }}
|
||||||
|
</p>
|
||||||
|
<p v-if="record?.code">
|
||||||
|
<strong>Kode:</strong>
|
||||||
|
{{ record.code }}
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</RecordConfirmation>
|
</RecordConfirmation>
|
||||||
|
|||||||
@@ -1,8 +1,198 @@
|
|||||||
<!-- Duplicated from content/counter/list.vue for chamber -->
|
|
||||||
<!-- TODO: Update logic and fields for chamber context -->
|
|
||||||
<template>
|
|
||||||
...existing code...
|
|
||||||
</template>
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
// ...existing code...
|
// Components
|
||||||
|
import Dialog from '~/components/pub/my-ui/modal/dialog.vue'
|
||||||
|
import Header from '~/components/pub/my-ui/nav-header/prep.vue'
|
||||||
|
import AppChamberList from '~/components/app/chamber/list.vue'
|
||||||
|
import AppChamberEntryForm from '~/components/app/chamber/entry-form.vue'
|
||||||
|
import RecordConfirmation from '~/components/pub/my-ui/confirmation/record-confirmation.vue'
|
||||||
|
|
||||||
|
// Constants
|
||||||
|
import { infraGroupCodesKeys } from '~/lib/constants'
|
||||||
|
|
||||||
|
// Helpers
|
||||||
|
import { usePaginatedList } from '~/composables/usePaginatedList'
|
||||||
|
import { toast } from '~/components/pub/ui/toast'
|
||||||
|
|
||||||
|
// Types
|
||||||
|
import { ActionEvents, type HeaderPrep } from '~/components/pub/my-ui/data/types'
|
||||||
|
import { InfraSchema, type InfraFormData } from '~/schemas/infra.schema'
|
||||||
|
|
||||||
|
// Handlers
|
||||||
|
import {
|
||||||
|
recId,
|
||||||
|
recAction,
|
||||||
|
recItem,
|
||||||
|
isReadonly,
|
||||||
|
isProcessing,
|
||||||
|
isFormEntryDialogOpen,
|
||||||
|
isRecordConfirmationOpen,
|
||||||
|
onResetState,
|
||||||
|
handleActionSave,
|
||||||
|
handleActionEdit,
|
||||||
|
handleActionRemove,
|
||||||
|
handleCancelForm,
|
||||||
|
} from '~/handlers/infra.handler'
|
||||||
|
|
||||||
|
// Services
|
||||||
|
import { getList, getDetail, getValueLabelList } from '~/services/infra.service'
|
||||||
|
|
||||||
|
const parents = ref<{ value: string | number; label: string }[]>([])
|
||||||
|
const title = ref('')
|
||||||
|
|
||||||
|
const {
|
||||||
|
data,
|
||||||
|
isLoading,
|
||||||
|
paginationMeta,
|
||||||
|
searchInput,
|
||||||
|
handlePageChange,
|
||||||
|
handleSearch,
|
||||||
|
fetchData: getItemList,
|
||||||
|
} = usePaginatedList({
|
||||||
|
fetchFn: async (params: any) => {
|
||||||
|
const result = await getList({
|
||||||
|
search: params.search,
|
||||||
|
sort: 'createdAt:asc',
|
||||||
|
'page-number': params['page-number'] || 2,
|
||||||
|
'page-size': params['page-size'] || 10,
|
||||||
|
'infraGroup-code': infraGroupCodesKeys.chamber,
|
||||||
|
includes: 'parent',
|
||||||
|
})
|
||||||
|
return { success: result.success || false, body: result.body || {} }
|
||||||
|
},
|
||||||
|
entityName: 'chamber',
|
||||||
|
})
|
||||||
|
|
||||||
|
const headerPrep: HeaderPrep = {
|
||||||
|
title: 'Kamar',
|
||||||
|
icon: 'i-lucide-layout-list',
|
||||||
|
refSearchNav: {
|
||||||
|
placeholder: 'Cari (min. 3 karakter)...',
|
||||||
|
minLength: 3,
|
||||||
|
debounceMs: 500,
|
||||||
|
showValidationFeedback: true,
|
||||||
|
onInput: (val: string) => {
|
||||||
|
searchInput.value = val
|
||||||
|
},
|
||||||
|
onClick: () => {},
|
||||||
|
onClear: () => {},
|
||||||
|
},
|
||||||
|
addNav: {
|
||||||
|
label: 'Tambah',
|
||||||
|
icon: 'i-lucide-plus',
|
||||||
|
onClick: () => {
|
||||||
|
recItem.value = null
|
||||||
|
recId.value = 0
|
||||||
|
isFormEntryDialogOpen.value = true
|
||||||
|
isReadonly.value = false
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
provide('rec_id', recId)
|
||||||
|
provide('rec_action', recAction)
|
||||||
|
provide('rec_item', recItem)
|
||||||
|
provide('table_data_loader', isLoading)
|
||||||
|
|
||||||
|
const getCurrentDetail = async (id: number | string) => {
|
||||||
|
const result = await getDetail(id)
|
||||||
|
if (result.success) {
|
||||||
|
const currentValue = result.body?.data || {}
|
||||||
|
recItem.value = currentValue
|
||||||
|
isFormEntryDialogOpen.value = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
watch([recId, recAction], () => {
|
||||||
|
switch (recAction.value) {
|
||||||
|
case ActionEvents.showDetail:
|
||||||
|
getCurrentDetail(recId.value)
|
||||||
|
title.value = 'Detail Kamar'
|
||||||
|
isReadonly.value = true
|
||||||
|
break
|
||||||
|
case ActionEvents.showEdit:
|
||||||
|
getCurrentDetail(recId.value)
|
||||||
|
title.value = 'Edit Kamar'
|
||||||
|
isReadonly.value = false
|
||||||
|
break
|
||||||
|
case ActionEvents.showConfirmDelete:
|
||||||
|
isRecordConfirmationOpen.value = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
onMounted(async () => {
|
||||||
|
parents.value = await getValueLabelList({ sort: 'createdAt:asc', 'infraGroup-code': infraGroupCodesKeys.floor })
|
||||||
|
await getItemList()
|
||||||
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<Header
|
||||||
|
v-model="searchInput"
|
||||||
|
:prep="headerPrep"
|
||||||
|
:ref-search-nav="headerPrep.refSearchNav"
|
||||||
|
@search="handleSearch"
|
||||||
|
class="mb-4 xl:mb-5"
|
||||||
|
/>
|
||||||
|
<AppChamberList
|
||||||
|
:data="data"
|
||||||
|
:pagination-meta="paginationMeta"
|
||||||
|
@page-change="handlePageChange"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<Dialog
|
||||||
|
v-model:open="isFormEntryDialogOpen"
|
||||||
|
:title="!!recItem ? title : 'Tambah Kamar'"
|
||||||
|
size="lg"
|
||||||
|
prevent-outside
|
||||||
|
@update:open="
|
||||||
|
(value: any) => {
|
||||||
|
onResetState()
|
||||||
|
isFormEntryDialogOpen = value
|
||||||
|
}
|
||||||
|
"
|
||||||
|
>
|
||||||
|
<AppChamberEntryForm
|
||||||
|
:schema="InfraSchema"
|
||||||
|
:parents="parents"
|
||||||
|
:values="recItem"
|
||||||
|
:is-loading="isProcessing"
|
||||||
|
:is-readonly="isReadonly"
|
||||||
|
@submit="
|
||||||
|
(values: InfraFormData | Record<string, any>, resetForm: () => void) => {
|
||||||
|
if (recId > 0) {
|
||||||
|
handleActionEdit(recId, values, getItemList, resetForm, toast)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
handleActionSave(values, getItemList, resetForm, toast)
|
||||||
|
}
|
||||||
|
"
|
||||||
|
@cancel="handleCancelForm"
|
||||||
|
/>
|
||||||
|
</Dialog>
|
||||||
|
|
||||||
|
<RecordConfirmation
|
||||||
|
v-model:open="isRecordConfirmationOpen"
|
||||||
|
action="delete"
|
||||||
|
:record="recItem"
|
||||||
|
@confirm="() => handleActionRemove(recId, getItemList, toast)"
|
||||||
|
@cancel=""
|
||||||
|
>
|
||||||
|
<template #default="{ record }">
|
||||||
|
<div class="text-sm">
|
||||||
|
<p>
|
||||||
|
<strong>ID:</strong>
|
||||||
|
{{ record?.id }}
|
||||||
|
</p>
|
||||||
|
<p v-if="record?.name">
|
||||||
|
<strong>Nama:</strong>
|
||||||
|
{{ record.name }}
|
||||||
|
</p>
|
||||||
|
<p v-if="record?.code">
|
||||||
|
<strong>Kode:</strong>
|
||||||
|
{{ record.code }}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</RecordConfirmation>
|
||||||
|
</template>
|
||||||
|
|||||||
@@ -2,9 +2,13 @@
|
|||||||
// Components
|
// Components
|
||||||
import Dialog from '~/components/pub/my-ui/modal/dialog.vue'
|
import Dialog from '~/components/pub/my-ui/modal/dialog.vue'
|
||||||
import Header from '~/components/pub/my-ui/nav-header/prep.vue'
|
import Header from '~/components/pub/my-ui/nav-header/prep.vue'
|
||||||
|
import AppCounterList from '~/components/app/counter/list.vue'
|
||||||
import AppCounterEntryForm from '~/components/app/counter/entry-form.vue'
|
import AppCounterEntryForm from '~/components/app/counter/entry-form.vue'
|
||||||
import RecordConfirmation from '~/components/pub/my-ui/confirmation/record-confirmation.vue'
|
import RecordConfirmation from '~/components/pub/my-ui/confirmation/record-confirmation.vue'
|
||||||
|
|
||||||
|
// Constants
|
||||||
|
import { infraGroupCodesKeys } from '~/lib/constants'
|
||||||
|
|
||||||
// Helpers
|
// Helpers
|
||||||
import { usePaginatedList } from '~/composables/usePaginatedList'
|
import { usePaginatedList } from '~/composables/usePaginatedList'
|
||||||
import { toast } from '~/components/pub/ui/toast'
|
import { toast } from '~/components/pub/ui/toast'
|
||||||
@@ -22,6 +26,7 @@ import {
|
|||||||
isProcessing,
|
isProcessing,
|
||||||
isFormEntryDialogOpen,
|
isFormEntryDialogOpen,
|
||||||
isRecordConfirmationOpen,
|
isRecordConfirmationOpen,
|
||||||
|
onResetState,
|
||||||
handleActionSave,
|
handleActionSave,
|
||||||
handleActionEdit,
|
handleActionEdit,
|
||||||
handleActionRemove,
|
handleActionRemove,
|
||||||
@@ -29,9 +34,10 @@ import {
|
|||||||
} from '~/handlers/infra.handler'
|
} from '~/handlers/infra.handler'
|
||||||
|
|
||||||
// Services
|
// Services
|
||||||
import { getInfras, getInfraDetail } from '~/services/infra.service'
|
import { getList, getDetail } from '~/services/infra.service'
|
||||||
|
|
||||||
const title = ref('')
|
const title = ref('')
|
||||||
|
|
||||||
const {
|
const {
|
||||||
data,
|
data,
|
||||||
isLoading,
|
isLoading,
|
||||||
@@ -39,10 +45,16 @@ const {
|
|||||||
searchInput,
|
searchInput,
|
||||||
handlePageChange,
|
handlePageChange,
|
||||||
handleSearch,
|
handleSearch,
|
||||||
fetchData: getCounterList,
|
fetchData: getItemList,
|
||||||
} = usePaginatedList({
|
} = usePaginatedList({
|
||||||
fetchFn: async ({ page, search }) => {
|
fetchFn: async (params: any) => {
|
||||||
const result = await getInfras({ search, page, infraGroup_code: 'counter' })
|
const result = await getList({
|
||||||
|
search: params.search,
|
||||||
|
sort: 'createdAt:asc',
|
||||||
|
'page-number': params['page-number'] || 0,
|
||||||
|
'page-size': params['page-size'] || 10,
|
||||||
|
'infraGroup-code': infraGroupCodesKeys.counter,
|
||||||
|
})
|
||||||
return { success: result.success || false, body: result.body || {} }
|
return { success: result.success || false, body: result.body || {} }
|
||||||
},
|
},
|
||||||
entityName: 'counter',
|
entityName: 'counter',
|
||||||
@@ -52,7 +64,7 @@ const headerPrep: HeaderPrep = {
|
|||||||
title: 'Counter',
|
title: 'Counter',
|
||||||
icon: 'i-lucide-layout-list',
|
icon: 'i-lucide-layout-list',
|
||||||
refSearchNav: {
|
refSearchNav: {
|
||||||
placeholder: 'Cari counter...',
|
placeholder: 'Cari (min. 3 karakter)...',
|
||||||
minLength: 3,
|
minLength: 3,
|
||||||
debounceMs: 500,
|
debounceMs: 500,
|
||||||
showValidationFeedback: true,
|
showValidationFeedback: true,
|
||||||
@@ -79,8 +91,8 @@ provide('rec_action', recAction)
|
|||||||
provide('rec_item', recItem)
|
provide('rec_item', recItem)
|
||||||
provide('table_data_loader', isLoading)
|
provide('table_data_loader', isLoading)
|
||||||
|
|
||||||
const getCurrentCounterDetail = async (id: number | string) => {
|
const getCurrentDetail = async (id: number | string) => {
|
||||||
const result = await getInfraDetail(id)
|
const result = await getDetail(id)
|
||||||
if (result.success) {
|
if (result.success) {
|
||||||
const currentValue = result.body?.data || {}
|
const currentValue = result.body?.data || {}
|
||||||
recItem.value = currentValue
|
recItem.value = currentValue
|
||||||
@@ -91,12 +103,12 @@ const getCurrentCounterDetail = async (id: number | string) => {
|
|||||||
watch([recId, recAction], () => {
|
watch([recId, recAction], () => {
|
||||||
switch (recAction.value) {
|
switch (recAction.value) {
|
||||||
case ActionEvents.showDetail:
|
case ActionEvents.showDetail:
|
||||||
getCurrentCounterDetail(recId.value)
|
getCurrentDetail(recId.value)
|
||||||
title.value = 'Detail Counter'
|
title.value = 'Detail Counter'
|
||||||
isReadonly.value = true
|
isReadonly.value = true
|
||||||
break
|
break
|
||||||
case ActionEvents.showEdit:
|
case ActionEvents.showEdit:
|
||||||
getCurrentCounterDetail(recId.value)
|
getCurrentDetail(recId.value)
|
||||||
title.value = 'Edit Counter'
|
title.value = 'Edit Counter'
|
||||||
isReadonly.value = false
|
isReadonly.value = false
|
||||||
break
|
break
|
||||||
@@ -107,15 +119,36 @@ watch([recId, recAction], () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
await getCounterList()
|
await getItemList()
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<Header v-model="searchInput" :prep="headerPrep" @search="handleSearch" class="mb-4 xl:mb-5" />
|
<Header
|
||||||
<AppCounterList :data="data" :pagination-meta="paginationMeta" @page-change="handlePageChange" />
|
v-model="searchInput"
|
||||||
|
:prep="headerPrep"
|
||||||
|
:ref-search-nav="headerPrep.refSearchNav"
|
||||||
|
@search="handleSearch"
|
||||||
|
class="mb-4 xl:mb-5"
|
||||||
|
/>
|
||||||
|
<AppCounterList
|
||||||
|
:data="data"
|
||||||
|
:pagination-meta="paginationMeta"
|
||||||
|
@page-change="handlePageChange"
|
||||||
|
/>
|
||||||
|
|
||||||
<Dialog v-model:open="isFormEntryDialogOpen" :title="!!recItem ? title : 'Tambah Counter'" size="lg" prevent-outside>
|
<Dialog
|
||||||
|
v-model:open="isFormEntryDialogOpen"
|
||||||
|
:title="!!recItem ? title : 'Tambah Counter'"
|
||||||
|
size="lg"
|
||||||
|
prevent-outside
|
||||||
|
@update:open="
|
||||||
|
(value: any) => {
|
||||||
|
onResetState()
|
||||||
|
isFormEntryDialogOpen = value
|
||||||
|
}
|
||||||
|
"
|
||||||
|
>
|
||||||
<AppCounterEntryForm
|
<AppCounterEntryForm
|
||||||
:schema="InfraSchema"
|
:schema="InfraSchema"
|
||||||
:values="recItem"
|
:values="recItem"
|
||||||
@@ -124,10 +157,10 @@ onMounted(async () => {
|
|||||||
@submit="
|
@submit="
|
||||||
(values: InfraFormData | Record<string, any>, resetForm: () => void) => {
|
(values: InfraFormData | Record<string, any>, resetForm: () => void) => {
|
||||||
if (recId > 0) {
|
if (recId > 0) {
|
||||||
handleActionEdit(recId, values, getCounterList, resetForm, toast)
|
handleActionEdit(recId, values, getItemList, resetForm, toast)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
handleActionSave(values, getCounterList, resetForm, toast)
|
handleActionSave(values, getItemList, resetForm, toast)
|
||||||
}
|
}
|
||||||
"
|
"
|
||||||
@cancel="handleCancelForm"
|
@cancel="handleCancelForm"
|
||||||
@@ -138,14 +171,23 @@ onMounted(async () => {
|
|||||||
v-model:open="isRecordConfirmationOpen"
|
v-model:open="isRecordConfirmationOpen"
|
||||||
action="delete"
|
action="delete"
|
||||||
:record="recItem"
|
:record="recItem"
|
||||||
@confirm="() => handleActionRemove(recId, getCounterList, toast)"
|
@confirm="() => handleActionRemove(recId, getItemList, toast)"
|
||||||
@cancel=""
|
@cancel=""
|
||||||
>
|
>
|
||||||
<template #default="{ record }">
|
<template #default="{ record }">
|
||||||
<div class="text-sm">
|
<div class="text-sm">
|
||||||
<p><strong>ID:</strong> {{ record?.id }}</p>
|
<p>
|
||||||
<p v-if="record?.name"><strong>Nama:</strong> {{ record.name }}</p>
|
<strong>ID:</strong>
|
||||||
<p v-if="record?.code"><strong>Kode:</strong> {{ record.code }}</p>
|
{{ record?.id }}
|
||||||
|
</p>
|
||||||
|
<p v-if="record?.name">
|
||||||
|
<strong>Nama:</strong>
|
||||||
|
{{ record.name }}
|
||||||
|
</p>
|
||||||
|
<p v-if="record?.code">
|
||||||
|
<strong>Kode:</strong>
|
||||||
|
{{ record.code }}
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</RecordConfirmation>
|
</RecordConfirmation>
|
||||||
|
|||||||
@@ -139,11 +139,11 @@ onMounted(() => {
|
|||||||
.join('')
|
.join('')
|
||||||
}}</AvatarFallback>
|
}}</AvatarFallback>
|
||||||
</Avatar>
|
</Avatar>
|
||||||
<div class="grid gap-1">
|
<div class="grid gap-1 min-w-0">
|
||||||
<p class="text-sm font-medium leading-none">
|
<p class="text-sm font-medium leading-none truncate">
|
||||||
{{ recentSales.name }}
|
{{ recentSales.name }}
|
||||||
</p>
|
</p>
|
||||||
<p class="text-sm text-muted-foreground">
|
<p class="text-sm text-muted-foreground truncate">
|
||||||
{{ recentSales.email }}
|
{{ recentSales.email }}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -0,0 +1,201 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
// Components
|
||||||
|
import Dialog from '~/components/pub/my-ui/modal/dialog.vue'
|
||||||
|
import Header from '~/components/pub/my-ui/nav-header/prep.vue'
|
||||||
|
import RecordConfirmation from '~/components/pub/my-ui/confirmation/record-confirmation.vue'
|
||||||
|
import AppDivisionPositionList from '~/components/app/division-position/list.vue'
|
||||||
|
import AppDivisionPositionEntryForm from '~/components/app/division-position/entry-form.vue'
|
||||||
|
|
||||||
|
// Helpers
|
||||||
|
import { usePaginatedList } from '~/composables/usePaginatedList'
|
||||||
|
import { toast } from '~/components/pub/ui/toast'
|
||||||
|
|
||||||
|
// Types
|
||||||
|
import { ActionEvents, type HeaderPrep } from '~/components/pub/my-ui/data/types'
|
||||||
|
import { DivisionPositionSchema, type DivisionPositionFormData } from '~/schemas/division-position.schema'
|
||||||
|
|
||||||
|
// Handlers
|
||||||
|
import {
|
||||||
|
recId,
|
||||||
|
recAction,
|
||||||
|
recItem,
|
||||||
|
isReadonly,
|
||||||
|
isProcessing,
|
||||||
|
isFormEntryDialogOpen,
|
||||||
|
isRecordConfirmationOpen,
|
||||||
|
onResetState,
|
||||||
|
handleActionSave,
|
||||||
|
handleActionEdit,
|
||||||
|
handleActionRemove,
|
||||||
|
handleCancelForm,
|
||||||
|
} from '~/handlers/division-position.handler'
|
||||||
|
|
||||||
|
// Services
|
||||||
|
import { getList, getDetail } from '~/services/division-position.service'
|
||||||
|
import { getValueLabelList as getDivisionLabelList } from '~/services/division.service'
|
||||||
|
import { getValueLabelList as getEmployeeLabelList } from '~/services/employee.service'
|
||||||
|
|
||||||
|
const divisions = ref<{ value: string | number; label: string }[]>([])
|
||||||
|
const employees = ref<{ value: string | number; label: string }[]>([])
|
||||||
|
const title = ref('')
|
||||||
|
|
||||||
|
const {
|
||||||
|
data,
|
||||||
|
isLoading,
|
||||||
|
paginationMeta,
|
||||||
|
searchInput,
|
||||||
|
handlePageChange,
|
||||||
|
handleSearch,
|
||||||
|
fetchData: getDivisionList,
|
||||||
|
} = usePaginatedList({
|
||||||
|
fetchFn: async (params: any) => {
|
||||||
|
const result = await getList({
|
||||||
|
search: params.search,
|
||||||
|
sort: 'createdAt:asc',
|
||||||
|
'page-number': params['page-number'] || 0,
|
||||||
|
'page-size': params['page-size'] || 10,
|
||||||
|
})
|
||||||
|
return { success: result.success || false, body: result.body || {} }
|
||||||
|
},
|
||||||
|
entityName: 'division',
|
||||||
|
})
|
||||||
|
|
||||||
|
const headerPrep: HeaderPrep = {
|
||||||
|
title: 'Divisi',
|
||||||
|
icon: 'i-lucide-box',
|
||||||
|
refSearchNav: {
|
||||||
|
placeholder: 'Cari (min. 3 karakter)...',
|
||||||
|
minLength: 3,
|
||||||
|
debounceMs: 500,
|
||||||
|
showValidationFeedback: true,
|
||||||
|
onInput: (value: string) => {
|
||||||
|
searchInput.value = value
|
||||||
|
},
|
||||||
|
onClick: () => {},
|
||||||
|
onClear: () => {},
|
||||||
|
},
|
||||||
|
addNav: {
|
||||||
|
label: 'Tambah',
|
||||||
|
icon: 'i-lucide-plus',
|
||||||
|
onClick: () => {
|
||||||
|
recItem.value = null
|
||||||
|
recId.value = 0
|
||||||
|
isFormEntryDialogOpen.value = true
|
||||||
|
isReadonly.value = false
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
provide('rec_id', recId)
|
||||||
|
provide('rec_action', recAction)
|
||||||
|
provide('rec_item', recItem)
|
||||||
|
provide('table_data_loader', isLoading)
|
||||||
|
|
||||||
|
const getCurrentDivisionDetail = async (id: number | string) => {
|
||||||
|
const result = await getDetail(id)
|
||||||
|
if (result.success) {
|
||||||
|
const currentValue = result.body?.data || {}
|
||||||
|
recItem.value = currentValue
|
||||||
|
isFormEntryDialogOpen.value = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Watch for row actions when recId or recAction changes
|
||||||
|
watch([recId, recAction], () => {
|
||||||
|
switch (recAction.value) {
|
||||||
|
case ActionEvents.showDetail:
|
||||||
|
getCurrentDivisionDetail(recId.value)
|
||||||
|
title.value = 'Detail Divisi'
|
||||||
|
isReadonly.value = true
|
||||||
|
break
|
||||||
|
case ActionEvents.showEdit:
|
||||||
|
getCurrentDivisionDetail(recId.value)
|
||||||
|
title.value = 'Edit Divisi'
|
||||||
|
isReadonly.value = false
|
||||||
|
break
|
||||||
|
case ActionEvents.showConfirmDelete:
|
||||||
|
isRecordConfirmationOpen.value = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
onMounted(async () => {
|
||||||
|
divisions.value = await getDivisionLabelList({ sort: 'createdAt:asc', 'page-size': 100 })
|
||||||
|
employees.value = await getEmployeeLabelList({ sort: 'createdAt:asc', 'page-size': 100 })
|
||||||
|
await getDivisionList()
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<Header
|
||||||
|
v-model="searchInput"
|
||||||
|
:prep="headerPrep"
|
||||||
|
:ref-search-nav="headerPrep.refSearchNav"
|
||||||
|
@search="handleSearch"
|
||||||
|
class="mb-4 xl:mb-5"
|
||||||
|
/>
|
||||||
|
<AppDivisionPositionList
|
||||||
|
:data="data"
|
||||||
|
:pagination-meta="paginationMeta"
|
||||||
|
@page-change="handlePageChange"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<Dialog
|
||||||
|
v-model:open="isFormEntryDialogOpen"
|
||||||
|
:title="!!recItem ? title : 'Tambah Divisi'"
|
||||||
|
size="lg"
|
||||||
|
prevent-outside
|
||||||
|
@update:open="
|
||||||
|
(value: any) => {
|
||||||
|
onResetState()
|
||||||
|
isFormEntryDialogOpen = value
|
||||||
|
}
|
||||||
|
"
|
||||||
|
>
|
||||||
|
<AppDivisionPositionEntryForm
|
||||||
|
:schema="DivisionPositionSchema"
|
||||||
|
:divisions="divisions"
|
||||||
|
:employees="employees"
|
||||||
|
:values="recItem"
|
||||||
|
:is-loading="isProcessing"
|
||||||
|
:is-readonly="isReadonly"
|
||||||
|
@submit="
|
||||||
|
(values: DivisionPositionFormData | Record<string, any>, resetForm: () => void) => {
|
||||||
|
console.log(values)
|
||||||
|
if (recId > 0) {
|
||||||
|
handleActionEdit(recId, values, getDivisionList, resetForm, toast)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
handleActionSave(values, getDivisionList, resetForm, toast)
|
||||||
|
}
|
||||||
|
"
|
||||||
|
@cancel="handleCancelForm"
|
||||||
|
/>
|
||||||
|
</Dialog>
|
||||||
|
|
||||||
|
<!-- Record Confirmation Modal -->
|
||||||
|
<RecordConfirmation
|
||||||
|
v-model:open="isRecordConfirmationOpen"
|
||||||
|
action="delete"
|
||||||
|
:record="recItem"
|
||||||
|
@confirm="() => handleActionRemove(recId, getDivisionList, toast)"
|
||||||
|
@cancel=""
|
||||||
|
>
|
||||||
|
<template #default="{ record }">
|
||||||
|
<div class="text-sm">
|
||||||
|
<p>
|
||||||
|
<strong>ID:</strong>
|
||||||
|
{{ record?.id }}
|
||||||
|
</p>
|
||||||
|
<p v-if="record?.name">
|
||||||
|
<strong>Nama:</strong>
|
||||||
|
{{ record.name }}
|
||||||
|
</p>
|
||||||
|
<p v-if="record?.code">
|
||||||
|
<strong>Kode:</strong>
|
||||||
|
{{ record.code }}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</RecordConfirmation>
|
||||||
|
</template>
|
||||||
@@ -13,6 +13,7 @@ import { toast } from '~/components/pub/ui/toast'
|
|||||||
// Types
|
// Types
|
||||||
import { ActionEvents, type HeaderPrep } from '~/components/pub/my-ui/data/types'
|
import { ActionEvents, type HeaderPrep } from '~/components/pub/my-ui/data/types'
|
||||||
import { DivisionSchema, type DivisionFormData } from '~/schemas/division.schema'
|
import { DivisionSchema, type DivisionFormData } from '~/schemas/division.schema'
|
||||||
|
import type { Division } from "~/models/division"
|
||||||
import type { TreeItem } from '~/models/_base'
|
import type { TreeItem } from '~/models/_base'
|
||||||
|
|
||||||
// Handlers
|
// Handlers
|
||||||
@@ -24,6 +25,7 @@ import {
|
|||||||
isProcessing,
|
isProcessing,
|
||||||
isFormEntryDialogOpen,
|
isFormEntryDialogOpen,
|
||||||
isRecordConfirmationOpen,
|
isRecordConfirmationOpen,
|
||||||
|
onResetState,
|
||||||
handleActionSave,
|
handleActionSave,
|
||||||
handleActionEdit,
|
handleActionEdit,
|
||||||
handleActionRemove,
|
handleActionRemove,
|
||||||
@@ -48,6 +50,7 @@ const {
|
|||||||
fetchFn: async (params: any) => {
|
fetchFn: async (params: any) => {
|
||||||
const result = await getList({
|
const result = await getList({
|
||||||
search: params.search,
|
search: params.search,
|
||||||
|
sort: 'createdAt:asc',
|
||||||
'page-number': params['page-number'] || 0,
|
'page-number': params['page-number'] || 0,
|
||||||
'page-size': params['page-size'] || 10,
|
'page-size': params['page-size'] || 10,
|
||||||
includes: 'parent,childrens',
|
includes: 'parent,childrens',
|
||||||
@@ -127,7 +130,8 @@ watch(
|
|||||||
})
|
})
|
||||||
if (result.success) {
|
if (result.success) {
|
||||||
const currentData = result.body.data || []
|
const currentData = result.body.data || []
|
||||||
divisionsTrees.value = getValueTreeItems(currentData || [])
|
const normalizedData = currentData.filter((division: Division) => !division.parent_id)
|
||||||
|
divisionsTrees.value = getValueTreeItems(normalizedData)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
@@ -156,6 +160,12 @@ onMounted(async () => {
|
|||||||
:title="!!recItem ? title : 'Tambah Divisi'"
|
:title="!!recItem ? title : 'Tambah Divisi'"
|
||||||
size="lg"
|
size="lg"
|
||||||
prevent-outside
|
prevent-outside
|
||||||
|
@update:open="
|
||||||
|
(value: any) => {
|
||||||
|
onResetState()
|
||||||
|
isFormEntryDialogOpen = value
|
||||||
|
}
|
||||||
|
"
|
||||||
>
|
>
|
||||||
<AppDivisionEntryForm
|
<AppDivisionEntryForm
|
||||||
:schema="DivisionSchema"
|
:schema="DivisionSchema"
|
||||||
|
|||||||
@@ -49,7 +49,7 @@ const refSearchNav: RefSearchNav = {
|
|||||||
|
|
||||||
async function getPatientList() {
|
async function getPatientList() {
|
||||||
isLoading.isTableLoading = true
|
isLoading.isTableLoading = true
|
||||||
const resp = await xfetch('/api/v1/patient')
|
const resp = await xfetch('/api/v1/encounter')
|
||||||
if (resp.success) {
|
if (resp.success) {
|
||||||
data.value = (resp.body as Record<string, any>).data
|
data.value = (resp.body as Record<string, any>).data
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,9 +7,15 @@ import { useRoute, useRouter } from 'vue-router'
|
|||||||
import CompTab from '~/components/pub/my-ui/comp-tab/comp-tab.vue'
|
import CompTab from '~/components/pub/my-ui/comp-tab/comp-tab.vue'
|
||||||
import type { TabItem } from '~/components/pub/my-ui/comp-tab/type'
|
import type { TabItem } from '~/components/pub/my-ui/comp-tab/type'
|
||||||
|
|
||||||
import Status from '~/components/app/encounter/status.vue'
|
import { getDetail } from '~/services/encounter.service'
|
||||||
|
|
||||||
import AssesmentFunctionList from '~/components/content/assesment-function/list.vue'
|
import AssesmentFunctionList from '~/components/content/assesment-function/list.vue'
|
||||||
import EarlyMedicalAssesmentList from '~/components/content/soapi/entry.vue'
|
import EarlyMedicalAssesmentList from '~/components/content/soapi/entry.vue'
|
||||||
|
import PrescriptionList from '~/components/content/prescription/list.vue'
|
||||||
|
import type { Encounter } from '~/models/encounter'
|
||||||
|
import Status from '~/components/app/encounter/status.vue'
|
||||||
|
// import AssesmentFunctionList from '~/components/content/assesment-function/list.vue'
|
||||||
|
import EarlyMedicalRehabList from '~/components/content/soapi/entry.vue'
|
||||||
|
|
||||||
const route = useRoute()
|
const route = useRoute()
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
@@ -22,6 +28,9 @@ const activeTab = computed({
|
|||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const id = typeof route.params.id == 'string' ? parseInt(route.params.id) : 0
|
||||||
|
const encounter = ref<Encounter>((await getDetail(id)) as Encounter)
|
||||||
|
|
||||||
const data = {
|
const data = {
|
||||||
noRm: 'RM21123',
|
noRm: 'RM21123',
|
||||||
nama: 'Ahmad Sutanto',
|
nama: 'Ahmad Sutanto',
|
||||||
@@ -38,13 +47,17 @@ const data = {
|
|||||||
const tabs: TabItem[] = [
|
const tabs: TabItem[] = [
|
||||||
{ value: 'status', label: 'Status Masuk/Keluar', component: Status },
|
{ value: 'status', label: 'Status Masuk/Keluar', component: Status },
|
||||||
{ value: 'early-medical-assessment', label: 'Pengkajian Awal Medis', component: EarlyMedicalAssesmentList },
|
{ value: 'early-medical-assessment', label: 'Pengkajian Awal Medis', component: EarlyMedicalAssesmentList },
|
||||||
{ value: 'rehab-medical-assessment', label: 'Pengkajian Awal Medis Rehabilitasi Medis' },
|
{
|
||||||
|
value: 'rehab-medical-assessment',
|
||||||
|
label: 'Pengkajian Awal Medis Rehabilitasi Medis',
|
||||||
|
component: EarlyMedicalRehabList,
|
||||||
|
},
|
||||||
{ value: 'function-assessment', label: 'Asesmen Fungsi', component: AssesmentFunctionList },
|
{ value: 'function-assessment', label: 'Asesmen Fungsi', component: AssesmentFunctionList },
|
||||||
{ value: 'therapy-protocol', label: 'Protokol Terapi' },
|
{ value: 'therapy-protocol', label: 'Protokol Terapi' },
|
||||||
{ value: 'education-assessment', label: 'Asesmen Kebutuhan Edukasi' },
|
{ value: 'education-assessment', label: 'Asesmen Kebutuhan Edukasi' },
|
||||||
{ value: 'consent', label: 'General Consent' },
|
{ value: 'consent', label: 'General Consent' },
|
||||||
{ value: 'patient-note', label: 'CPRJ' },
|
{ value: 'patient-note', label: 'CPRJ' },
|
||||||
{ value: 'prescription', label: 'Order Obat' },
|
{ value: 'prescription', label: 'Order Obat', component: PrescriptionList },
|
||||||
{ value: 'device', label: 'Order Alkes' },
|
{ value: 'device', label: 'Order Alkes' },
|
||||||
{ value: 'mcu-radiology', label: 'Order Radiologi' },
|
{ value: 'mcu-radiology', label: 'Order Radiologi' },
|
||||||
{ value: 'mcu-lab-pc', label: 'Order Lab PK' },
|
{ value: 'mcu-lab-pc', label: 'Order Lab PK' },
|
||||||
@@ -66,6 +79,10 @@ const tabs: TabItem[] = [
|
|||||||
<PubMyUiNavContentBa label="Kembali ke Daftar Kunjungan" />
|
<PubMyUiNavContentBa label="Kembali ke Daftar Kunjungan" />
|
||||||
</div>
|
</div>
|
||||||
<AppEncounterQuickInfo :data="data" />
|
<AppEncounterQuickInfo :data="data" />
|
||||||
<CompTab :data="tabs" :initial-active-tab="activeTab" @change-tab="activeTab = $event" />
|
<CompTab
|
||||||
|
:data="tabs"
|
||||||
|
:initial-active-tab="activeTab"
|
||||||
|
@change-tab="activeTab = $event"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ import {
|
|||||||
isProcessing,
|
isProcessing,
|
||||||
isFormEntryDialogOpen,
|
isFormEntryDialogOpen,
|
||||||
isRecordConfirmationOpen,
|
isRecordConfirmationOpen,
|
||||||
|
onResetState,
|
||||||
handleActionSave,
|
handleActionSave,
|
||||||
handleActionEdit,
|
handleActionEdit,
|
||||||
handleActionRemove,
|
handleActionRemove,
|
||||||
@@ -33,7 +34,7 @@ import {
|
|||||||
import { getList, getDetail } from '~/services/material.service'
|
import { getList, getDetail } from '~/services/material.service'
|
||||||
import { getValueLabelList as getUomList } from '~/services/uom.service'
|
import { getValueLabelList as getUomList } from '~/services/uom.service'
|
||||||
|
|
||||||
const uoms = ref<{ value: string; label: string }[]>([])
|
const uoms = ref<{ value: string | number; label: string }[]>([])
|
||||||
const title = ref('')
|
const title = ref('')
|
||||||
|
|
||||||
const {
|
const {
|
||||||
@@ -48,6 +49,7 @@ const {
|
|||||||
fetchFn: async (params: any) => {
|
fetchFn: async (params: any) => {
|
||||||
const result = await getList({
|
const result = await getList({
|
||||||
search: params.search,
|
search: params.search,
|
||||||
|
sort: 'createdAt:asc',
|
||||||
'page-number': params['page-number'] || 0,
|
'page-number': params['page-number'] || 0,
|
||||||
'page-size': params['page-size'] || 10,
|
'page-size': params['page-size'] || 10,
|
||||||
})
|
})
|
||||||
@@ -129,13 +131,23 @@ onMounted(async () => {
|
|||||||
:ref-search-nav="headerPrep.refSearchNav"
|
:ref-search-nav="headerPrep.refSearchNav"
|
||||||
class="mb-4 xl:mb-5"
|
class="mb-4 xl:mb-5"
|
||||||
/>
|
/>
|
||||||
<AppEquipmentList :data="data" :pagination-meta="paginationMeta" @page-change="handlePageChange" />
|
<AppEquipmentList
|
||||||
|
:data="data"
|
||||||
|
:pagination-meta="paginationMeta"
|
||||||
|
@page-change="handlePageChange"
|
||||||
|
/>
|
||||||
|
|
||||||
<Dialog
|
<Dialog
|
||||||
v-model:open="isFormEntryDialogOpen"
|
v-model:open="isFormEntryDialogOpen"
|
||||||
:title="!!recItem ? title : 'Tambah Perlengkapan'"
|
:title="!!recItem ? title : 'Tambah Perlengkapan'"
|
||||||
size="lg"
|
size="lg"
|
||||||
prevent-outside
|
prevent-outside
|
||||||
|
@update:open="
|
||||||
|
(value: any) => {
|
||||||
|
onResetState()
|
||||||
|
isFormEntryDialogOpen = value
|
||||||
|
}
|
||||||
|
"
|
||||||
>
|
>
|
||||||
<AppEquipmentEntryForm
|
<AppEquipmentEntryForm
|
||||||
:schema="MaterialSchema"
|
:schema="MaterialSchema"
|
||||||
@@ -166,9 +178,18 @@ onMounted(async () => {
|
|||||||
>
|
>
|
||||||
<template #default="{ record }">
|
<template #default="{ record }">
|
||||||
<div class="text-sm">
|
<div class="text-sm">
|
||||||
<p><strong>ID:</strong> {{ record?.id }}</p>
|
<p>
|
||||||
<p v-if="record?.name"><strong>Nama:</strong> {{ record.name }}</p>
|
<strong>ID:</strong>
|
||||||
<p v-if="record?.code"><strong>Kode:</strong> {{ record.code }}</p>
|
{{ record?.id }}
|
||||||
|
</p>
|
||||||
|
<p v-if="record?.name">
|
||||||
|
<strong>Nama:</strong>
|
||||||
|
{{ record.name }}
|
||||||
|
</p>
|
||||||
|
<p v-if="record?.code">
|
||||||
|
<strong>Kode:</strong>
|
||||||
|
{{ record.code }}
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</RecordConfirmation>
|
</RecordConfirmation>
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ import {
|
|||||||
isProcessing,
|
isProcessing,
|
||||||
isFormEntryDialogOpen,
|
isFormEntryDialogOpen,
|
||||||
isRecordConfirmationOpen,
|
isRecordConfirmationOpen,
|
||||||
|
onResetState,
|
||||||
handleActionSave,
|
handleActionSave,
|
||||||
handleActionEdit,
|
handleActionEdit,
|
||||||
handleActionRemove,
|
handleActionRemove,
|
||||||
@@ -35,7 +36,7 @@ import {
|
|||||||
// Services
|
// Services
|
||||||
import { getList, getDetail, getValueLabelList } from '~/services/infra.service'
|
import { getList, getDetail, getValueLabelList } from '~/services/infra.service'
|
||||||
|
|
||||||
const parents = ref<{ value: string; label: string }[]>([])
|
const parents = ref<{ value: string | number; label: string }[]>([])
|
||||||
const title = ref('')
|
const title = ref('')
|
||||||
|
|
||||||
const {
|
const {
|
||||||
@@ -50,6 +51,7 @@ const {
|
|||||||
fetchFn: async (params: any) => {
|
fetchFn: async (params: any) => {
|
||||||
const result = await getList({
|
const result = await getList({
|
||||||
search: params.search,
|
search: params.search,
|
||||||
|
sort: 'createdAt:asc',
|
||||||
'page-number': params['page-number'] || 2,
|
'page-number': params['page-number'] || 2,
|
||||||
'page-size': params['page-size'] || 10,
|
'page-size': params['page-size'] || 10,
|
||||||
'infraGroup-code': infraGroupCodesKeys.floor,
|
'infraGroup-code': infraGroupCodesKeys.floor,
|
||||||
@@ -64,7 +66,7 @@ const headerPrep: HeaderPrep = {
|
|||||||
title: 'Lantai',
|
title: 'Lantai',
|
||||||
icon: 'i-lucide-layout-list',
|
icon: 'i-lucide-layout-list',
|
||||||
refSearchNav: {
|
refSearchNav: {
|
||||||
placeholder: 'Cari lantai...',
|
placeholder: 'Cari (min. 3 karakter)...',
|
||||||
minLength: 3,
|
minLength: 3,
|
||||||
debounceMs: 500,
|
debounceMs: 500,
|
||||||
showValidationFeedback: true,
|
showValidationFeedback: true,
|
||||||
@@ -119,16 +121,37 @@ watch([recId, recAction], () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
parents.value = await getValueLabelList({ 'infraGroup-code': infraGroupCodesKeys.building })
|
parents.value = await getValueLabelList({ sort: 'createdAt:asc', 'infraGroup-code': infraGroupCodesKeys.building })
|
||||||
await getItemList()
|
await getItemList()
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<Header v-model="searchInput" :prep="headerPrep" @search="handleSearch" class="mb-4 xl:mb-5" />
|
<Header
|
||||||
<AppFloorList :data="data" :pagination-meta="paginationMeta" @page-change="handlePageChange" />
|
v-model="searchInput"
|
||||||
|
:prep="headerPrep"
|
||||||
|
:ref-search-nav="headerPrep.refSearchNav"
|
||||||
|
@search="handleSearch"
|
||||||
|
class="mb-4 xl:mb-5"
|
||||||
|
/>
|
||||||
|
<AppFloorList
|
||||||
|
:data="data"
|
||||||
|
:pagination-meta="paginationMeta"
|
||||||
|
@page-change="handlePageChange"
|
||||||
|
/>
|
||||||
|
|
||||||
<Dialog v-model:open="isFormEntryDialogOpen" :title="!!recItem ? title : 'Tambah Gedung'" size="lg" prevent-outside>
|
<Dialog
|
||||||
|
v-model:open="isFormEntryDialogOpen"
|
||||||
|
:title="!!recItem ? title : 'Tambah Lantai'"
|
||||||
|
size="lg"
|
||||||
|
prevent-outside
|
||||||
|
@update:open="
|
||||||
|
(value: any) => {
|
||||||
|
onResetState()
|
||||||
|
isFormEntryDialogOpen = value
|
||||||
|
}
|
||||||
|
"
|
||||||
|
>
|
||||||
<AppFloorEntryForm
|
<AppFloorEntryForm
|
||||||
:schema="InfraSchema"
|
:schema="InfraSchema"
|
||||||
:parents="parents"
|
:parents="parents"
|
||||||
@@ -157,9 +180,18 @@ onMounted(async () => {
|
|||||||
>
|
>
|
||||||
<template #default="{ record }">
|
<template #default="{ record }">
|
||||||
<div class="text-sm">
|
<div class="text-sm">
|
||||||
<p><strong>ID:</strong> {{ record?.id }}</p>
|
<p>
|
||||||
<p v-if="record?.name"><strong>Nama:</strong> {{ record.name }}</p>
|
<strong>ID:</strong>
|
||||||
<p v-if="record?.code"><strong>Kode:</strong> {{ record.code }}</p>
|
{{ record?.id }}
|
||||||
|
</p>
|
||||||
|
<p v-if="record?.name">
|
||||||
|
<strong>Nama:</strong>
|
||||||
|
{{ record.name }}
|
||||||
|
</p>
|
||||||
|
<p v-if="record?.code">
|
||||||
|
<strong>Kode:</strong>
|
||||||
|
{{ record.code }}
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</RecordConfirmation>
|
</RecordConfirmation>
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ import {
|
|||||||
isProcessing,
|
isProcessing,
|
||||||
isFormEntryDialogOpen,
|
isFormEntryDialogOpen,
|
||||||
isRecordConfirmationOpen,
|
isRecordConfirmationOpen,
|
||||||
|
onResetState,
|
||||||
handleActionSave,
|
handleActionSave,
|
||||||
handleActionEdit,
|
handleActionEdit,
|
||||||
handleActionRemove,
|
handleActionRemove,
|
||||||
@@ -48,6 +49,7 @@ const {
|
|||||||
fetchFn: async (params: any) => {
|
fetchFn: async (params: any) => {
|
||||||
const result = await getList({
|
const result = await getList({
|
||||||
search: params.search,
|
search: params.search,
|
||||||
|
sort: 'createdAt:asc',
|
||||||
'page-number': params['page-number'] || 0,
|
'page-number': params['page-number'] || 0,
|
||||||
'page-size': params['page-size'] || 10,
|
'page-size': params['page-size'] || 10,
|
||||||
})
|
})
|
||||||
@@ -129,13 +131,23 @@ onMounted(async () => {
|
|||||||
@search="handleSearch"
|
@search="handleSearch"
|
||||||
class="mb-4 xl:mb-5"
|
class="mb-4 xl:mb-5"
|
||||||
/>
|
/>
|
||||||
<AppInstallationList :data="data" :pagination-meta="paginationMeta" @page-change="handlePageChange" />
|
<AppInstallationList
|
||||||
|
:data="data"
|
||||||
|
:pagination-meta="paginationMeta"
|
||||||
|
@page-change="handlePageChange"
|
||||||
|
/>
|
||||||
|
|
||||||
<Dialog
|
<Dialog
|
||||||
v-model:open="isFormEntryDialogOpen"
|
v-model:open="isFormEntryDialogOpen"
|
||||||
:title="!!recItem ? title : 'Tambah Instalasi'"
|
:title="!!recItem ? title : 'Tambah Instalasi'"
|
||||||
size="lg"
|
size="lg"
|
||||||
prevent-outside
|
prevent-outside
|
||||||
|
@update:open="
|
||||||
|
(value: any) => {
|
||||||
|
onResetState()
|
||||||
|
isFormEntryDialogOpen = value
|
||||||
|
}
|
||||||
|
"
|
||||||
>
|
>
|
||||||
<AppInstallationEntryForm
|
<AppInstallationEntryForm
|
||||||
:schema="InstallationSchema"
|
:schema="InstallationSchema"
|
||||||
@@ -166,9 +178,18 @@ onMounted(async () => {
|
|||||||
>
|
>
|
||||||
<template #default="{ record }">
|
<template #default="{ record }">
|
||||||
<div class="text-sm">
|
<div class="text-sm">
|
||||||
<p><strong>ID:</strong> {{ record?.id }}</p>
|
<p>
|
||||||
<p v-if="record?.name"><strong>Nama:</strong> {{ record.name }}</p>
|
<strong>ID:</strong>
|
||||||
<p v-if="record?.code"><strong>Kode:</strong> {{ record.code }}</p>
|
{{ record?.id }}
|
||||||
|
</p>
|
||||||
|
<p v-if="record?.name">
|
||||||
|
<strong>Nama:</strong>
|
||||||
|
{{ record.name }}
|
||||||
|
</p>
|
||||||
|
<p v-if="record?.code">
|
||||||
|
<strong>Kode:</strong>
|
||||||
|
{{ record.code }}
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</RecordConfirmation>
|
</RecordConfirmation>
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ import { toast } from '~/components/pub/ui/toast'
|
|||||||
|
|
||||||
// Types
|
// Types
|
||||||
import { ActionEvents, type HeaderPrep } from '~/components/pub/my-ui/data/types'
|
import { ActionEvents, type HeaderPrep } from '~/components/pub/my-ui/data/types'
|
||||||
import { BaseSchema, type BaseFormData } from '~/schemas/my-ui.schema'
|
import { BaseSchema, type BaseFormData } from '~/schemas/base.schema'
|
||||||
|
|
||||||
// Handlers
|
// Handlers
|
||||||
import {
|
import {
|
||||||
@@ -23,6 +23,7 @@ import {
|
|||||||
isProcessing,
|
isProcessing,
|
||||||
isFormEntryDialogOpen,
|
isFormEntryDialogOpen,
|
||||||
isRecordConfirmationOpen,
|
isRecordConfirmationOpen,
|
||||||
|
onResetState,
|
||||||
handleActionSave,
|
handleActionSave,
|
||||||
handleActionEdit,
|
handleActionEdit,
|
||||||
handleActionRemove,
|
handleActionRemove,
|
||||||
@@ -46,6 +47,7 @@ const {
|
|||||||
fetchFn: async (params: any) => {
|
fetchFn: async (params: any) => {
|
||||||
const result = await getList({
|
const result = await getList({
|
||||||
search: params.search,
|
search: params.search,
|
||||||
|
sort: 'createdAt:asc',
|
||||||
'page-number': params['page-number'] || 0,
|
'page-number': params['page-number'] || 0,
|
||||||
'page-size': params['page-size'] || 10,
|
'page-size': params['page-size'] || 10,
|
||||||
})
|
})
|
||||||
@@ -126,13 +128,23 @@ onMounted(async () => {
|
|||||||
@search="handleSearch"
|
@search="handleSearch"
|
||||||
class="mb-4 xl:mb-5"
|
class="mb-4 xl:mb-5"
|
||||||
/>
|
/>
|
||||||
<AppMedicineGroupList :data="data" :pagination-meta="paginationMeta" @page-change="handlePageChange" />
|
<AppMedicineGroupList
|
||||||
|
:data="data"
|
||||||
|
:pagination-meta="paginationMeta"
|
||||||
|
@page-change="handlePageChange"
|
||||||
|
/>
|
||||||
|
|
||||||
<Dialog
|
<Dialog
|
||||||
v-model:open="isFormEntryDialogOpen"
|
v-model:open="isFormEntryDialogOpen"
|
||||||
:title="!!recItem ? title : 'Tambah Kelompok Obat'"
|
:title="!!recItem ? title : 'Tambah Kelompok Obat'"
|
||||||
size="lg"
|
size="lg"
|
||||||
prevent-outside
|
prevent-outside
|
||||||
|
@update:open="
|
||||||
|
(value: any) => {
|
||||||
|
onResetState()
|
||||||
|
isFormEntryDialogOpen = value
|
||||||
|
}
|
||||||
|
"
|
||||||
>
|
>
|
||||||
<AppMedicineGroupEntryForm
|
<AppMedicineGroupEntryForm
|
||||||
:schema="BaseSchema"
|
:schema="BaseSchema"
|
||||||
@@ -162,9 +174,18 @@ onMounted(async () => {
|
|||||||
>
|
>
|
||||||
<template #default="{ record }">
|
<template #default="{ record }">
|
||||||
<div class="text-sm">
|
<div class="text-sm">
|
||||||
<p><strong>ID:</strong> {{ record?.id }}</p>
|
<p>
|
||||||
<p v-if="record?.name"><strong>Nama:</strong> {{ record.name }}</p>
|
<strong>ID:</strong>
|
||||||
<p v-if="record?.code"><strong>Kode:</strong> {{ record.code }}</p>
|
{{ record?.id }}
|
||||||
|
</p>
|
||||||
|
<p v-if="record?.name">
|
||||||
|
<strong>Nama:</strong>
|
||||||
|
{{ record.name }}
|
||||||
|
</p>
|
||||||
|
<p v-if="record?.code">
|
||||||
|
<strong>Kode:</strong>
|
||||||
|
{{ record.code }}
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</RecordConfirmation>
|
</RecordConfirmation>
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ import { toast } from '~/components/pub/ui/toast'
|
|||||||
|
|
||||||
// Types
|
// Types
|
||||||
import { ActionEvents, type HeaderPrep } from '~/components/pub/my-ui/data/types'
|
import { ActionEvents, type HeaderPrep } from '~/components/pub/my-ui/data/types'
|
||||||
import { BaseSchema, type BaseFormData } from '~/schemas/my-ui.schema'
|
import { BaseSchema, type BaseFormData } from '~/schemas/base.schema'
|
||||||
|
|
||||||
// Handlers
|
// Handlers
|
||||||
import {
|
import {
|
||||||
@@ -23,6 +23,7 @@ import {
|
|||||||
isProcessing,
|
isProcessing,
|
||||||
isFormEntryDialogOpen,
|
isFormEntryDialogOpen,
|
||||||
isRecordConfirmationOpen,
|
isRecordConfirmationOpen,
|
||||||
|
onResetState,
|
||||||
handleActionSave,
|
handleActionSave,
|
||||||
handleActionEdit,
|
handleActionEdit,
|
||||||
handleActionRemove,
|
handleActionRemove,
|
||||||
@@ -46,6 +47,7 @@ const {
|
|||||||
fetchFn: async (params: any) => {
|
fetchFn: async (params: any) => {
|
||||||
const result = await getList({
|
const result = await getList({
|
||||||
search: params.search,
|
search: params.search,
|
||||||
|
sort: 'createdAt:asc',
|
||||||
'page-number': params['page-number'] || 0,
|
'page-number': params['page-number'] || 0,
|
||||||
'page-size': params['page-size'] || 10,
|
'page-size': params['page-size'] || 10,
|
||||||
})
|
})
|
||||||
@@ -126,13 +128,23 @@ onMounted(async () => {
|
|||||||
@search="handleSearch"
|
@search="handleSearch"
|
||||||
class="mb-4 xl:mb-5"
|
class="mb-4 xl:mb-5"
|
||||||
/>
|
/>
|
||||||
<AppMedicineMethodList :data="data" :pagination-meta="paginationMeta" @page-change="handlePageChange" />
|
<AppMedicineMethodList
|
||||||
|
:data="data"
|
||||||
|
:pagination-meta="paginationMeta"
|
||||||
|
@page-change="handlePageChange"
|
||||||
|
/>
|
||||||
|
|
||||||
<Dialog
|
<Dialog
|
||||||
v-model:open="isFormEntryDialogOpen"
|
v-model:open="isFormEntryDialogOpen"
|
||||||
:title="!!recItem ? title : 'Tambah Metode Obat'"
|
:title="!!recItem ? title : 'Tambah Metode Obat'"
|
||||||
size="lg"
|
size="lg"
|
||||||
prevent-outside
|
prevent-outside
|
||||||
|
@update:open="
|
||||||
|
(value: any) => {
|
||||||
|
onResetState()
|
||||||
|
isFormEntryDialogOpen = value
|
||||||
|
}
|
||||||
|
"
|
||||||
>
|
>
|
||||||
<AppMedicineMethodEntryForm
|
<AppMedicineMethodEntryForm
|
||||||
:schema="BaseSchema"
|
:schema="BaseSchema"
|
||||||
@@ -162,9 +174,18 @@ onMounted(async () => {
|
|||||||
>
|
>
|
||||||
<template #default="{ record }">
|
<template #default="{ record }">
|
||||||
<div class="text-sm">
|
<div class="text-sm">
|
||||||
<p><strong>ID:</strong> {{ record?.id }}</p>
|
<p>
|
||||||
<p v-if="record?.name"><strong>Nama:</strong> {{ record.name }}</p>
|
<strong>ID:</strong>
|
||||||
<p v-if="record?.code"><strong>Kode:</strong> {{ record.code }}</p>
|
{{ record?.id }}
|
||||||
|
</p>
|
||||||
|
<p v-if="record?.name">
|
||||||
|
<strong>Nama:</strong>
|
||||||
|
{{ record.name }}
|
||||||
|
</p>
|
||||||
|
<p v-if="record?.code">
|
||||||
|
<strong>Kode:</strong>
|
||||||
|
{{ record.code }}
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</RecordConfirmation>
|
</RecordConfirmation>
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ import {
|
|||||||
isProcessing,
|
isProcessing,
|
||||||
isFormEntryDialogOpen,
|
isFormEntryDialogOpen,
|
||||||
isRecordConfirmationOpen,
|
isRecordConfirmationOpen,
|
||||||
|
onResetState,
|
||||||
handleActionSave,
|
handleActionSave,
|
||||||
handleActionEdit,
|
handleActionEdit,
|
||||||
handleActionRemove,
|
handleActionRemove,
|
||||||
@@ -55,6 +56,7 @@ const {
|
|||||||
fetchFn: async (params: any) => {
|
fetchFn: async (params: any) => {
|
||||||
const result = await getList({
|
const result = await getList({
|
||||||
search: params.search,
|
search: params.search,
|
||||||
|
sort: 'createdAt:asc',
|
||||||
'page-number': params['page-number'] || 0,
|
'page-number': params['page-number'] || 0,
|
||||||
'page-size': params['page-size'] || 10,
|
'page-size': params['page-size'] || 10,
|
||||||
includes: 'medicineGroup,medicineMethod,uom',
|
includes: 'medicineGroup,medicineMethod,uom',
|
||||||
@@ -123,9 +125,9 @@ watch([recId, recAction], () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
medicineGroups.value = await getMedicineGroupList()
|
medicineGroups.value = await getMedicineGroupList({ sort: 'createdAt:asc', 'page-size': 100 })
|
||||||
medicineMethods.value = await getMedicineMethodList()
|
medicineMethods.value = await getMedicineMethodList({ sort: 'createdAt:asc', 'page-size': 100 })
|
||||||
uoms.value = await getUomList()
|
uoms.value = await getUomList({ sort: 'createdAt:asc', 'page-size': 100 })
|
||||||
await getMedicineList()
|
await getMedicineList()
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
@@ -138,9 +140,24 @@ onMounted(async () => {
|
|||||||
:ref-search-nav="headerPrep.refSearchNav"
|
:ref-search-nav="headerPrep.refSearchNav"
|
||||||
class="mb-4 xl:mb-5"
|
class="mb-4 xl:mb-5"
|
||||||
/>
|
/>
|
||||||
<AppMedicineList :data="data" :pagination-meta="paginationMeta" @page-change="handlePageChange" />
|
<AppMedicineList
|
||||||
|
:data="data"
|
||||||
|
:pagination-meta="paginationMeta"
|
||||||
|
@page-change="handlePageChange"
|
||||||
|
/>
|
||||||
|
|
||||||
<Dialog v-model:open="isFormEntryDialogOpen" :title="!!recItem ? title : 'Tambah Obat'" size="lg" prevent-outside>
|
<Dialog
|
||||||
|
v-model:open="isFormEntryDialogOpen"
|
||||||
|
:title="!!recItem ? title : 'Tambah Obat'"
|
||||||
|
size="lg"
|
||||||
|
prevent-outside
|
||||||
|
@update:open="
|
||||||
|
(value: any) => {
|
||||||
|
onResetState()
|
||||||
|
isFormEntryDialogOpen = value
|
||||||
|
}
|
||||||
|
"
|
||||||
|
>
|
||||||
<AppMedicineEntryForm
|
<AppMedicineEntryForm
|
||||||
:schema="MedicineSchema"
|
:schema="MedicineSchema"
|
||||||
:values="recItem"
|
:values="recItem"
|
||||||
@@ -172,9 +189,18 @@ onMounted(async () => {
|
|||||||
>
|
>
|
||||||
<template #default="{ record }">
|
<template #default="{ record }">
|
||||||
<div class="text-sm">
|
<div class="text-sm">
|
||||||
<p><strong>ID:</strong> {{ record?.id }}</p>
|
<p>
|
||||||
<p v-if="record?.name"><strong>Nama:</strong> {{ record.name }}</p>
|
<strong>ID:</strong>
|
||||||
<p v-if="record?.code"><strong>Kode:</strong> {{ record.code }}</p>
|
{{ record?.id }}
|
||||||
|
</p>
|
||||||
|
<p v-if="record?.name">
|
||||||
|
<strong>Nama:</strong>
|
||||||
|
{{ record.name }}
|
||||||
|
</p>
|
||||||
|
<p v-if="record?.code">
|
||||||
|
<strong>Kode:</strong>
|
||||||
|
{{ record.code }}
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</RecordConfirmation>
|
</RecordConfirmation>
|
||||||
|
|||||||
@@ -0,0 +1,194 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
// Components
|
||||||
|
import Dialog from '~/components/pub/my-ui/modal/dialog.vue'
|
||||||
|
import Header from '~/components/pub/my-ui/nav-header/prep.vue'
|
||||||
|
import AppPublicScreenList from '~/components/app/public-screen/list.vue'
|
||||||
|
import AppPublicScreenEntryForm from '~/components/app/public-screen/entry-form.vue'
|
||||||
|
import RecordConfirmation from '~/components/pub/my-ui/confirmation/record-confirmation.vue'
|
||||||
|
|
||||||
|
// Constants
|
||||||
|
import { infraGroupCodesKeys } from '~/lib/constants'
|
||||||
|
|
||||||
|
// Helpers
|
||||||
|
import { usePaginatedList } from '~/composables/usePaginatedList'
|
||||||
|
import { toast } from '~/components/pub/ui/toast'
|
||||||
|
|
||||||
|
// Types
|
||||||
|
import { ActionEvents, type HeaderPrep } from '~/components/pub/my-ui/data/types'
|
||||||
|
import { InfraSchema, type InfraFormData } from '~/schemas/infra.schema'
|
||||||
|
|
||||||
|
// Handlers
|
||||||
|
import {
|
||||||
|
recId,
|
||||||
|
recAction,
|
||||||
|
recItem,
|
||||||
|
isReadonly,
|
||||||
|
isProcessing,
|
||||||
|
isFormEntryDialogOpen,
|
||||||
|
isRecordConfirmationOpen,
|
||||||
|
onResetState,
|
||||||
|
handleActionSave,
|
||||||
|
handleActionEdit,
|
||||||
|
handleActionRemove,
|
||||||
|
handleCancelForm,
|
||||||
|
} from '~/handlers/infra.handler'
|
||||||
|
|
||||||
|
// Services
|
||||||
|
import { getList, getDetail } from '~/services/infra.service'
|
||||||
|
|
||||||
|
const title = ref('')
|
||||||
|
|
||||||
|
const {
|
||||||
|
data,
|
||||||
|
isLoading,
|
||||||
|
paginationMeta,
|
||||||
|
searchInput,
|
||||||
|
handlePageChange,
|
||||||
|
handleSearch,
|
||||||
|
fetchData: getItemList,
|
||||||
|
} = usePaginatedList({
|
||||||
|
fetchFn: async (params: any) => {
|
||||||
|
const result = await getList({
|
||||||
|
search: params.search,
|
||||||
|
sort: 'createdAt:asc',
|
||||||
|
'page-number': params['page-number'] || 0,
|
||||||
|
'page-size': params['page-size'] || 10,
|
||||||
|
'infraGroup-code': infraGroupCodesKeys['public-screen'],
|
||||||
|
})
|
||||||
|
return { success: result.success || false, body: result.body || {} }
|
||||||
|
},
|
||||||
|
entityName: 'counter',
|
||||||
|
})
|
||||||
|
|
||||||
|
const headerPrep: HeaderPrep = {
|
||||||
|
title: 'Layar Publik',
|
||||||
|
icon: 'i-lucide-layout-list',
|
||||||
|
refSearchNav: {
|
||||||
|
placeholder: 'Cari (min. 3 karakter)...',
|
||||||
|
minLength: 3,
|
||||||
|
debounceMs: 500,
|
||||||
|
showValidationFeedback: true,
|
||||||
|
onInput: (val: string) => {
|
||||||
|
searchInput.value = val
|
||||||
|
},
|
||||||
|
onClick: () => {},
|
||||||
|
onClear: () => {},
|
||||||
|
},
|
||||||
|
addNav: {
|
||||||
|
label: 'Tambah',
|
||||||
|
icon: 'i-lucide-plus',
|
||||||
|
onClick: () => {
|
||||||
|
recItem.value = null
|
||||||
|
recId.value = 0
|
||||||
|
isFormEntryDialogOpen.value = true
|
||||||
|
isReadonly.value = false
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
provide('rec_id', recId)
|
||||||
|
provide('rec_action', recAction)
|
||||||
|
provide('rec_item', recItem)
|
||||||
|
provide('table_data_loader', isLoading)
|
||||||
|
|
||||||
|
const getCurrentDetail = async (id: number | string) => {
|
||||||
|
const result = await getDetail(id)
|
||||||
|
if (result.success) {
|
||||||
|
const currentValue = result.body?.data || {}
|
||||||
|
recItem.value = currentValue
|
||||||
|
isFormEntryDialogOpen.value = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
watch([recId, recAction], () => {
|
||||||
|
switch (recAction.value) {
|
||||||
|
case ActionEvents.showDetail:
|
||||||
|
getCurrentDetail(recId.value)
|
||||||
|
title.value = 'Detail Layar Publik'
|
||||||
|
isReadonly.value = true
|
||||||
|
break
|
||||||
|
case ActionEvents.showEdit:
|
||||||
|
getCurrentDetail(recId.value)
|
||||||
|
title.value = 'Edit Layar Publik'
|
||||||
|
isReadonly.value = false
|
||||||
|
break
|
||||||
|
case ActionEvents.showConfirmDelete:
|
||||||
|
isRecordConfirmationOpen.value = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
onMounted(async () => {
|
||||||
|
await getItemList()
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<Header
|
||||||
|
v-model="searchInput"
|
||||||
|
:prep="headerPrep"
|
||||||
|
:ref-search-nav="headerPrep.refSearchNav"
|
||||||
|
@search="handleSearch"
|
||||||
|
class="mb-4 xl:mb-5"
|
||||||
|
/>
|
||||||
|
<AppPublicScreenList
|
||||||
|
:data="data"
|
||||||
|
:pagination-meta="paginationMeta"
|
||||||
|
@page-change="handlePageChange"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<Dialog
|
||||||
|
v-model:open="isFormEntryDialogOpen"
|
||||||
|
:title="!!recItem ? title : 'Tambah Layar Publik'"
|
||||||
|
size="lg"
|
||||||
|
prevent-outside
|
||||||
|
@update:open="
|
||||||
|
(value: any) => {
|
||||||
|
onResetState()
|
||||||
|
isFormEntryDialogOpen = value
|
||||||
|
}
|
||||||
|
"
|
||||||
|
>
|
||||||
|
<AppPublicScreenEntryForm
|
||||||
|
:schema="InfraSchema"
|
||||||
|
:values="recItem"
|
||||||
|
:is-loading="isProcessing"
|
||||||
|
:is-readonly="isReadonly"
|
||||||
|
@submit="
|
||||||
|
(values: InfraFormData | Record<string, any>, resetForm: () => void) => {
|
||||||
|
if (recId > 0) {
|
||||||
|
handleActionEdit(recId, values, getItemList, resetForm, toast)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
handleActionSave(values, getItemList, resetForm, toast)
|
||||||
|
}
|
||||||
|
"
|
||||||
|
@cancel="handleCancelForm"
|
||||||
|
/>
|
||||||
|
</Dialog>
|
||||||
|
|
||||||
|
<RecordConfirmation
|
||||||
|
v-model:open="isRecordConfirmationOpen"
|
||||||
|
action="delete"
|
||||||
|
:record="recItem"
|
||||||
|
@confirm="() => handleActionRemove(recId, getItemList, toast)"
|
||||||
|
@cancel=""
|
||||||
|
>
|
||||||
|
<template #default="{ record }">
|
||||||
|
<div class="text-sm">
|
||||||
|
<p>
|
||||||
|
<strong>ID:</strong>
|
||||||
|
{{ record?.id }}
|
||||||
|
</p>
|
||||||
|
<p v-if="record?.name">
|
||||||
|
<strong>Nama:</strong>
|
||||||
|
{{ record.name }}
|
||||||
|
</p>
|
||||||
|
<p v-if="record?.code">
|
||||||
|
<strong>Kode:</strong>
|
||||||
|
{{ record.code }}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</RecordConfirmation>
|
||||||
|
</template>
|
||||||
@@ -26,6 +26,7 @@ import {
|
|||||||
isProcessing,
|
isProcessing,
|
||||||
isFormEntryDialogOpen,
|
isFormEntryDialogOpen,
|
||||||
isRecordConfirmationOpen,
|
isRecordConfirmationOpen,
|
||||||
|
onResetState,
|
||||||
handleActionSave,
|
handleActionSave,
|
||||||
handleActionEdit,
|
handleActionEdit,
|
||||||
handleActionRemove,
|
handleActionRemove,
|
||||||
@@ -37,11 +38,14 @@ import { getList, getDetail, getValueLabelList } from '~/services/infra.service'
|
|||||||
import { getValueLabelList as getSpecialistList } from '~/services/specialist.service'
|
import { getValueLabelList as getSpecialistList } from '~/services/specialist.service'
|
||||||
import { getValueLabelList as getSubspecialistList } from '~/services/subspecialist.service'
|
import { getValueLabelList as getSubspecialistList } from '~/services/subspecialist.service'
|
||||||
import { getValueLabelList as getUnitList } from '~/services/unit.service'
|
import { getValueLabelList as getUnitList } from '~/services/unit.service'
|
||||||
|
import { getDetail as getItemDetail } from '~/services/item.service'
|
||||||
|
|
||||||
const parents = ref<{ value: string | number; label: string }[]>([])
|
const parents = ref<{ value: string | number; label: string }[]>([])
|
||||||
const specialists = ref<{ value: string; label: string }[]>([])
|
const specialists = ref<{ value: string | number; label: string }[]>([])
|
||||||
const subspecialists = ref<{ value: string; label: string }[]>([])
|
const specialistsFiltered = ref<{ value: string | number; label: string }[]>([])
|
||||||
const units = ref<{ value: string; label: string }[]>([])
|
const subspecialists = ref<{ value: string | number; label: string }[]>([])
|
||||||
|
const subspecialistsFiltered = ref<{ value: string | number; label: string }[]>([])
|
||||||
|
const units = ref<{ value: string | number; label: string }[]>([])
|
||||||
const selectedUnit = ref<string | number | null>(null)
|
const selectedUnit = ref<string | number | null>(null)
|
||||||
const selectedSpecialist = ref<string | number | null>(null)
|
const selectedSpecialist = ref<string | number | null>(null)
|
||||||
const title = ref('')
|
const title = ref('')
|
||||||
@@ -58,10 +62,11 @@ const {
|
|||||||
fetchFn: async (params: any) => {
|
fetchFn: async (params: any) => {
|
||||||
const result = await getList({
|
const result = await getList({
|
||||||
search: params.search,
|
search: params.search,
|
||||||
|
sort: 'createdAt:asc',
|
||||||
'page-number': params['page-number'] || 2,
|
'page-number': params['page-number'] || 2,
|
||||||
'page-size': params['page-size'] || 10,
|
'page-size': params['page-size'] || 10,
|
||||||
'infraGroup-code': infraGroupCodesKeys.room,
|
'infraGroup-code': infraGroupCodesKeys.room,
|
||||||
includes: 'parent,specialist,subspecialist,unit',
|
includes: 'parent',
|
||||||
})
|
})
|
||||||
return { success: result.success || false, body: result.body || {} }
|
return { success: result.success || false, body: result.body || {} }
|
||||||
},
|
},
|
||||||
@@ -72,7 +77,7 @@ const headerPrep: HeaderPrep = {
|
|||||||
title: 'Ruangan',
|
title: 'Ruangan',
|
||||||
icon: 'i-lucide-layout-list',
|
icon: 'i-lucide-layout-list',
|
||||||
refSearchNav: {
|
refSearchNav: {
|
||||||
placeholder: 'Cari Ruangan...',
|
placeholder: 'Cari (min. 3 karakter)...',
|
||||||
minLength: 3,
|
minLength: 3,
|
||||||
debounceMs: 500,
|
debounceMs: 500,
|
||||||
showValidationFeedback: true,
|
showValidationFeedback: true,
|
||||||
@@ -103,6 +108,34 @@ const getCurrentDetail = async (id: number | string) => {
|
|||||||
const result = await getDetail(id)
|
const result = await getDetail(id)
|
||||||
if (result.success) {
|
if (result.success) {
|
||||||
const currentValue = result.body?.data || {}
|
const currentValue = result.body?.data || {}
|
||||||
|
if (currentValue.item_id) {
|
||||||
|
const itemResult = await getItemDetail(currentValue.item_id)
|
||||||
|
if (itemResult.success) {
|
||||||
|
currentValue.item = itemResult.body?.data || {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (currentValue.rooms) {
|
||||||
|
const rooms: any = Array.isArray(currentValue.rooms) && currentValue.rooms.length > 0 ? currentValue.rooms[0] : {}
|
||||||
|
specialistsFiltered.value = rooms?.specialist
|
||||||
|
? [
|
||||||
|
{
|
||||||
|
value: rooms.specialist?.id ? Number(rooms.specialist.id) : '',
|
||||||
|
label: rooms.specialist?.name || '',
|
||||||
|
},
|
||||||
|
]
|
||||||
|
: []
|
||||||
|
subspecialistsFiltered.value = rooms?.subspecialist
|
||||||
|
? [
|
||||||
|
{
|
||||||
|
value: rooms.subspecialist?.id ? Number(rooms.subspecialist.id) : '',
|
||||||
|
label: rooms.subspecialist?.name || '',
|
||||||
|
},
|
||||||
|
]
|
||||||
|
: []
|
||||||
|
currentValue.unit_id = rooms?.unit_id || null
|
||||||
|
currentValue.specialist_id = rooms?.specialist_id || null
|
||||||
|
currentValue.subspecialist_id = rooms?.subspecialist_id || null
|
||||||
|
}
|
||||||
recItem.value = currentValue
|
recItem.value = currentValue
|
||||||
isFormEntryDialogOpen.value = true
|
isFormEntryDialogOpen.value = true
|
||||||
}
|
}
|
||||||
@@ -126,42 +159,67 @@ watch([recId, recAction], () => {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
watch(selectedUnit, async (val) => {
|
watch(selectedUnit, async (value: string | number | null) => {
|
||||||
if (val) {
|
specialistsFiltered.value = []
|
||||||
specialists.value = await getSpecialistList({ 'unit-id': val, 'page-size': 100 })
|
if (value) {
|
||||||
selectedSpecialist.value = null
|
selectedSpecialist.value = null
|
||||||
subspecialists.value = []
|
specialistsFiltered.value = specialists.value.filter((item: any) => Number(item.parent) === Number(value))
|
||||||
|
subspecialistsFiltered.value = []
|
||||||
} else {
|
} else {
|
||||||
specialists.value = []
|
|
||||||
selectedSpecialist.value = null
|
selectedSpecialist.value = null
|
||||||
subspecialists.value = []
|
specialistsFiltered.value = []
|
||||||
|
subspecialistsFiltered.value = []
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
watch(selectedSpecialist, async (val) => {
|
watch(selectedSpecialist, async (value: string | number | null) => {
|
||||||
if (val) {
|
subspecialistsFiltered.value = []
|
||||||
subspecialists.value = await getSubspecialistList({ 'specialist-id': val, 'page-size': 100 })
|
if (value) {
|
||||||
|
subspecialistsFiltered.value = subspecialists.value.filter((item: any) => Number(item.parent) === Number(value))
|
||||||
} else {
|
} else {
|
||||||
subspecialists.value = []
|
subspecialistsFiltered.value = []
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
parents.value = await getValueLabelList({ 'infraGroup-code': infraGroupCodesKeys.floor })
|
parents.value = await getValueLabelList({ sort: 'createdAt:asc', 'infraGroup-code': infraGroupCodesKeys.floor })
|
||||||
units.value = await getUnitList({ 'page-size': 100 })
|
specialists.value = await getSpecialistList({ sort: 'createdAt:asc', 'page-size': 100 })
|
||||||
|
subspecialists.value = await getSubspecialistList({ sort: 'createdAt:asc', 'page-size': 100 })
|
||||||
|
units.value = await getUnitList({ sort: 'createdAt:asc', 'page-size': 100 })
|
||||||
await getItemList()
|
await getItemList()
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<Header v-model="searchInput" :prep="headerPrep" @search="handleSearch" class="mb-4 xl:mb-5" />
|
<Header
|
||||||
<AppRoomList :data="data" :pagination-meta="paginationMeta" @page-change="handlePageChange" />
|
v-model="searchInput"
|
||||||
|
:prep="headerPrep"
|
||||||
|
:ref-search-nav="headerPrep.refSearchNav"
|
||||||
|
@search="handleSearch"
|
||||||
|
class="mb-4 xl:mb-5"
|
||||||
|
/>
|
||||||
|
<AppRoomList
|
||||||
|
:data="data"
|
||||||
|
:pagination-meta="paginationMeta"
|
||||||
|
@page-change="handlePageChange"
|
||||||
|
/>
|
||||||
|
|
||||||
<Dialog v-model:open="isFormEntryDialogOpen" :title="!!recItem ? title : 'Tambah Ruangan'" size="lg" prevent-outside>
|
<Dialog
|
||||||
|
v-model:open="isFormEntryDialogOpen"
|
||||||
|
:title="!!recItem ? title : 'Tambah Ruangan'"
|
||||||
|
size="lg"
|
||||||
|
prevent-outside
|
||||||
|
@update:open="
|
||||||
|
(value: any) => {
|
||||||
|
onResetState()
|
||||||
|
isFormEntryDialogOpen = value
|
||||||
|
}
|
||||||
|
"
|
||||||
|
>
|
||||||
<AppRoomEntryForm
|
<AppRoomEntryForm
|
||||||
:schema="InfraSchema"
|
:schema="InfraSchema"
|
||||||
:specialists="specialists"
|
:specialists="specialistsFiltered"
|
||||||
:subspecialists="subspecialists"
|
:subspecialists="subspecialistsFiltered"
|
||||||
:units="units"
|
:units="units"
|
||||||
:parents="parents"
|
:parents="parents"
|
||||||
:values="recItem"
|
:values="recItem"
|
||||||
@@ -191,9 +249,18 @@ onMounted(async () => {
|
|||||||
>
|
>
|
||||||
<template #default="{ record }">
|
<template #default="{ record }">
|
||||||
<div class="text-sm">
|
<div class="text-sm">
|
||||||
<p><strong>ID:</strong> {{ record?.id }}</p>
|
<p>
|
||||||
<p v-if="record?.name"><strong>Nama:</strong> {{ record.name }}</p>
|
<strong>ID:</strong>
|
||||||
<p v-if="record?.code"><strong>Kode:</strong> {{ record.code }}</p>
|
{{ record?.id }}
|
||||||
|
</p>
|
||||||
|
<p v-if="record?.name">
|
||||||
|
<strong>Nama:</strong>
|
||||||
|
{{ record.name }}
|
||||||
|
</p>
|
||||||
|
<p v-if="record?.code">
|
||||||
|
<strong>Kode:</strong>
|
||||||
|
{{ record.code }}
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</RecordConfirmation>
|
</RecordConfirmation>
|
||||||
|
|||||||
@@ -1,16 +1,38 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { computed } from 'vue'
|
import { computed } from 'vue'
|
||||||
import { useRoute, useRouter } from 'vue-router'
|
import { useRoute } from 'vue-router'
|
||||||
|
import { useQueryMode } from '@/composables/useQueryMode' // asumsikan ini ada
|
||||||
|
|
||||||
import EarlyMedicalAssesmentList from './list.vue'
|
import SoapiList from './list.vue'
|
||||||
import EarlyMedicalAssesmentForm from './form.vue'
|
import EarlyForm from './form.vue'
|
||||||
|
import RehabForm from './form-rehab.vue'
|
||||||
|
import FunctionForm from './form-function.vue'
|
||||||
|
|
||||||
|
const route = useRoute()
|
||||||
|
const type = computed(() => (route.query.tab as string) || 'early-medical-assessment')
|
||||||
|
|
||||||
const { mode, openForm, backToList } = useQueryMode('mode')
|
const { mode, openForm, backToList } = useQueryMode('mode')
|
||||||
|
|
||||||
|
const formMap = {
|
||||||
|
'early-medical-assessment': EarlyForm,
|
||||||
|
'rehab-medical-assessment': RehabForm,
|
||||||
|
'function-assessment': FunctionForm,
|
||||||
|
}
|
||||||
|
|
||||||
|
const ActiveForm = computed(() => formMap[type.value] || EarlyForm)
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<EarlyMedicalAssesmentList v-if="mode === 'list'" @add="openForm" />
|
<SoapiList
|
||||||
<EarlyMedicalAssesmentForm v-else @back="backToList" />
|
v-if="mode === 'list'"
|
||||||
|
@add="openForm"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<component
|
||||||
|
v-else
|
||||||
|
:is="ActiveForm"
|
||||||
|
@back="backToList"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@@ -0,0 +1,45 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import Entry from '~/components/app/soapi/entry.vue'
|
||||||
|
import Dialog from '~/components/pub/my-ui/modal/dialog.vue'
|
||||||
|
|
||||||
|
const isOpen = ref(false)
|
||||||
|
const data = ref([])
|
||||||
|
const isLoading = reactive<DataTableLoader>({
|
||||||
|
isTableLoading: false,
|
||||||
|
})
|
||||||
|
|
||||||
|
async function getPatientList() {
|
||||||
|
isLoading.isTableLoading = true
|
||||||
|
const resp = await xfetch('/api/v1/patient')
|
||||||
|
if (resp.success) {
|
||||||
|
data.value = (resp.body as Record<string, any>).data
|
||||||
|
}
|
||||||
|
isLoading.isTableLoading = false
|
||||||
|
}
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
getPatientList()
|
||||||
|
})
|
||||||
|
|
||||||
|
function handleClick(type: string) {
|
||||||
|
console.log(type)
|
||||||
|
isOpen.value = true
|
||||||
|
}
|
||||||
|
|
||||||
|
provide('table_data_loader', isLoading)
|
||||||
|
</script>
|
||||||
|
<template>
|
||||||
|
<Entry
|
||||||
|
type="function"
|
||||||
|
:exclude-fields="['prim-compl', 'sec-compl']"
|
||||||
|
@click="handleClick"
|
||||||
|
/>
|
||||||
|
<Dialog
|
||||||
|
v-model:open="isOpen"
|
||||||
|
title="Pilih Prosedur"
|
||||||
|
size="xl"
|
||||||
|
prevent-outside
|
||||||
|
>
|
||||||
|
<AppIcdMultiselectPicker :data="data" />
|
||||||
|
</Dialog>
|
||||||
|
</template>
|
||||||
@@ -0,0 +1,45 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import Entry from '~/components/app/soapi/entry.vue'
|
||||||
|
import Dialog from '~/components/pub/my-ui/modal/dialog.vue'
|
||||||
|
|
||||||
|
const isOpen = ref(false)
|
||||||
|
const data = ref([])
|
||||||
|
const isLoading = reactive<DataTableLoader>({
|
||||||
|
isTableLoading: false,
|
||||||
|
})
|
||||||
|
|
||||||
|
async function getPatientList() {
|
||||||
|
isLoading.isTableLoading = true
|
||||||
|
const resp = await xfetch('/api/v1/patient')
|
||||||
|
if (resp.success) {
|
||||||
|
data.value = (resp.body as Record<string, any>).data
|
||||||
|
}
|
||||||
|
isLoading.isTableLoading = false
|
||||||
|
}
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
getPatientList()
|
||||||
|
})
|
||||||
|
|
||||||
|
function handleClick(type: string) {
|
||||||
|
console.log(type)
|
||||||
|
isOpen.value = true
|
||||||
|
}
|
||||||
|
|
||||||
|
provide('table_data_loader', isLoading)
|
||||||
|
</script>
|
||||||
|
<template>
|
||||||
|
<Entry
|
||||||
|
type="early-rehab"
|
||||||
|
:exclude-fields="['prim-compl', 'sec-compl']"
|
||||||
|
@click="handleClick"
|
||||||
|
/>
|
||||||
|
<Dialog
|
||||||
|
v-model:open="isOpen"
|
||||||
|
title="Pilih Prosedur"
|
||||||
|
size="xl"
|
||||||
|
prevent-outside
|
||||||
|
>
|
||||||
|
<AppIcdMultiselectPicker :data="data" />
|
||||||
|
</Dialog>
|
||||||
|
</template>
|
||||||
@@ -23,6 +23,7 @@ import {
|
|||||||
isProcessing,
|
isProcessing,
|
||||||
isFormEntryDialogOpen,
|
isFormEntryDialogOpen,
|
||||||
isRecordConfirmationOpen,
|
isRecordConfirmationOpen,
|
||||||
|
onResetState,
|
||||||
handleActionSave,
|
handleActionSave,
|
||||||
handleActionEdit,
|
handleActionEdit,
|
||||||
handleActionRemove,
|
handleActionRemove,
|
||||||
@@ -48,6 +49,7 @@ const {
|
|||||||
fetchFn: async (params: any) => {
|
fetchFn: async (params: any) => {
|
||||||
const result = await getList({
|
const result = await getList({
|
||||||
search: params.search,
|
search: params.search,
|
||||||
|
sort: 'createdAt:asc',
|
||||||
'page-number': params['page-number'] || 0,
|
'page-number': params['page-number'] || 0,
|
||||||
'page-size': params['page-size'] || 10,
|
'page-size': params['page-size'] || 10,
|
||||||
includes: 'unit',
|
includes: 'unit',
|
||||||
@@ -130,13 +132,23 @@ onMounted(async () => {
|
|||||||
@search="handleSearch"
|
@search="handleSearch"
|
||||||
class="mb-4 xl:mb-5"
|
class="mb-4 xl:mb-5"
|
||||||
/>
|
/>
|
||||||
<AppSpecialistList :data="data" :pagination-meta="paginationMeta" @page-change="handlePageChange" />
|
<AppSpecialistList
|
||||||
|
:data="data"
|
||||||
|
:pagination-meta="paginationMeta"
|
||||||
|
@page-change="handlePageChange"
|
||||||
|
/>
|
||||||
|
|
||||||
<Dialog
|
<Dialog
|
||||||
v-model:open="isFormEntryDialogOpen"
|
v-model:open="isFormEntryDialogOpen"
|
||||||
:title="!!recItem ? title : 'Tambah Spesialis'"
|
:title="!!recItem ? title : 'Tambah Spesialis'"
|
||||||
size="lg"
|
size="lg"
|
||||||
prevent-outside
|
prevent-outside
|
||||||
|
@update:open="
|
||||||
|
(value: any) => {
|
||||||
|
onResetState()
|
||||||
|
isFormEntryDialogOpen = value
|
||||||
|
}
|
||||||
|
"
|
||||||
>
|
>
|
||||||
<AppSpecialistEntryForm
|
<AppSpecialistEntryForm
|
||||||
:schema="SpecialistSchema"
|
:schema="SpecialistSchema"
|
||||||
@@ -167,9 +179,18 @@ onMounted(async () => {
|
|||||||
>
|
>
|
||||||
<template #default="{ record }">
|
<template #default="{ record }">
|
||||||
<div class="text-sm">
|
<div class="text-sm">
|
||||||
<p><strong>ID:</strong> {{ record?.id }}</p>
|
<p>
|
||||||
<p v-if="record?.name"><strong>Nama:</strong> {{ record.name }}</p>
|
<strong>ID:</strong>
|
||||||
<p v-if="record?.code"><strong>Kode:</strong> {{ record.code }}</p>
|
{{ record?.id }}
|
||||||
|
</p>
|
||||||
|
<p v-if="record?.name">
|
||||||
|
<strong>Nama:</strong>
|
||||||
|
{{ record.name }}
|
||||||
|
</p>
|
||||||
|
<p v-if="record?.code">
|
||||||
|
<strong>Kode:</strong>
|
||||||
|
{{ record.code }}
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</RecordConfirmation>
|
</RecordConfirmation>
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ import {
|
|||||||
isProcessing,
|
isProcessing,
|
||||||
isFormEntryDialogOpen,
|
isFormEntryDialogOpen,
|
||||||
isRecordConfirmationOpen,
|
isRecordConfirmationOpen,
|
||||||
|
onResetState,
|
||||||
handleActionSave,
|
handleActionSave,
|
||||||
handleActionEdit,
|
handleActionEdit,
|
||||||
handleActionRemove,
|
handleActionRemove,
|
||||||
@@ -48,6 +49,7 @@ const {
|
|||||||
fetchFn: async (params: any) => {
|
fetchFn: async (params: any) => {
|
||||||
const result = await getList({
|
const result = await getList({
|
||||||
search: params.search,
|
search: params.search,
|
||||||
|
sort: 'createdAt:asc',
|
||||||
'page-number': params['page-number'] || 0,
|
'page-number': params['page-number'] || 0,
|
||||||
'page-size': params['page-size'] || 10,
|
'page-size': params['page-size'] || 10,
|
||||||
includes: 'specialist',
|
includes: 'specialist',
|
||||||
@@ -130,13 +132,23 @@ onMounted(async () => {
|
|||||||
@search="handleSearch"
|
@search="handleSearch"
|
||||||
class="mb-4 xl:mb-5"
|
class="mb-4 xl:mb-5"
|
||||||
/>
|
/>
|
||||||
<AppSubSpecialistList :data="data" :pagination-meta="paginationMeta" @page-change="handlePageChange" />
|
<AppSubSpecialistList
|
||||||
|
:data="data"
|
||||||
|
:pagination-meta="paginationMeta"
|
||||||
|
@page-change="handlePageChange"
|
||||||
|
/>
|
||||||
|
|
||||||
<Dialog
|
<Dialog
|
||||||
v-model:open="isFormEntryDialogOpen"
|
v-model:open="isFormEntryDialogOpen"
|
||||||
:title="!!recItem ? title : 'Tambah Sub Spesialis'"
|
:title="!!recItem ? title : 'Tambah Sub Spesialis'"
|
||||||
size="lg"
|
size="lg"
|
||||||
prevent-outside
|
prevent-outside
|
||||||
|
@update:open="
|
||||||
|
(value: any) => {
|
||||||
|
onResetState()
|
||||||
|
isFormEntryDialogOpen = value
|
||||||
|
}
|
||||||
|
"
|
||||||
>
|
>
|
||||||
<AppSubSpecialistEntryForm
|
<AppSubSpecialistEntryForm
|
||||||
:schema="SubspecialistSchema"
|
:schema="SubspecialistSchema"
|
||||||
@@ -167,9 +179,18 @@ onMounted(async () => {
|
|||||||
>
|
>
|
||||||
<template #default="{ record }">
|
<template #default="{ record }">
|
||||||
<div class="text-sm">
|
<div class="text-sm">
|
||||||
<p><strong>ID:</strong> {{ record?.id }}</p>
|
<p>
|
||||||
<p v-if="record?.name"><strong>Nama:</strong> {{ record.name }}</p>
|
<strong>ID:</strong>
|
||||||
<p v-if="record?.code"><strong>Kode:</strong> {{ record.code }}</p>
|
{{ record?.id }}
|
||||||
|
</p>
|
||||||
|
<p v-if="record?.name">
|
||||||
|
<strong>Nama:</strong>
|
||||||
|
{{ record.name }}
|
||||||
|
</p>
|
||||||
|
<p v-if="record?.code">
|
||||||
|
<strong>Kode:</strong>
|
||||||
|
{{ record.code }}
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</RecordConfirmation>
|
</RecordConfirmation>
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ import {
|
|||||||
isProcessing,
|
isProcessing,
|
||||||
isFormEntryDialogOpen,
|
isFormEntryDialogOpen,
|
||||||
isRecordConfirmationOpen,
|
isRecordConfirmationOpen,
|
||||||
|
onResetState,
|
||||||
handleActionSave,
|
handleActionSave,
|
||||||
handleActionEdit,
|
handleActionEdit,
|
||||||
handleActionRemove,
|
handleActionRemove,
|
||||||
@@ -46,7 +47,12 @@ const {
|
|||||||
fetchData: getToolsList,
|
fetchData: getToolsList,
|
||||||
} = usePaginatedList({
|
} = usePaginatedList({
|
||||||
fetchFn: async (params: any) => {
|
fetchFn: async (params: any) => {
|
||||||
const result = await getList({ search: params.search, 'page-number': params['page-number'] || 0 })
|
const result = await getList({
|
||||||
|
search: params.search,
|
||||||
|
sort: 'createdAt:asc',
|
||||||
|
'page-number': params['page-number'] || 0,
|
||||||
|
'page-size': params['page-size'] || 10,
|
||||||
|
})
|
||||||
return { success: result.success || false, body: result.body || {} }
|
return { success: result.success || false, body: result.body || {} }
|
||||||
},
|
},
|
||||||
entityName: 'device',
|
entityName: 'device',
|
||||||
@@ -130,13 +136,23 @@ onMounted(async () => {
|
|||||||
:ref-search-nav="headerPrep.refSearchNav"
|
:ref-search-nav="headerPrep.refSearchNav"
|
||||||
class="mb-4 xl:mb-5"
|
class="mb-4 xl:mb-5"
|
||||||
/>
|
/>
|
||||||
<AppToolsList :data="data" :pagination-meta="paginationMeta" @page-change="handlePageChange" />
|
<AppToolsList
|
||||||
|
:data="data"
|
||||||
|
:pagination-meta="paginationMeta"
|
||||||
|
@page-change="handlePageChange"
|
||||||
|
/>
|
||||||
|
|
||||||
<Dialog
|
<Dialog
|
||||||
v-model:open="isFormEntryDialogOpen"
|
v-model:open="isFormEntryDialogOpen"
|
||||||
:title="!!recItem ? title : 'Tambah Peralatan'"
|
:title="!!recItem ? title : 'Tambah Peralatan'"
|
||||||
size="lg"
|
size="lg"
|
||||||
prevent-outside
|
prevent-outside
|
||||||
|
@update:open="
|
||||||
|
(value: any) => {
|
||||||
|
onResetState()
|
||||||
|
isFormEntryDialogOpen = value
|
||||||
|
}
|
||||||
|
"
|
||||||
>
|
>
|
||||||
<AppToolsEntryForm
|
<AppToolsEntryForm
|
||||||
:schema="DeviceSchema"
|
:schema="DeviceSchema"
|
||||||
@@ -167,9 +183,18 @@ onMounted(async () => {
|
|||||||
>
|
>
|
||||||
<template #default="{ record }">
|
<template #default="{ record }">
|
||||||
<div class="text-sm">
|
<div class="text-sm">
|
||||||
<p><strong>ID:</strong> {{ record?.id }}</p>
|
<p>
|
||||||
<p v-if="record?.name"><strong>Nama:</strong> {{ record.name }}</p>
|
<strong>ID:</strong>
|
||||||
<p v-if="record?.code"><strong>Kode:</strong> {{ record.code }}</p>
|
{{ record?.id }}
|
||||||
|
</p>
|
||||||
|
<p v-if="record?.name">
|
||||||
|
<strong>Nama:</strong>
|
||||||
|
{{ record.name }}
|
||||||
|
</p>
|
||||||
|
<p v-if="record?.code">
|
||||||
|
<strong>Kode:</strong>
|
||||||
|
{{ record.code }}
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</RecordConfirmation>
|
</RecordConfirmation>
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ import {
|
|||||||
isProcessing,
|
isProcessing,
|
||||||
isFormEntryDialogOpen,
|
isFormEntryDialogOpen,
|
||||||
isRecordConfirmationOpen,
|
isRecordConfirmationOpen,
|
||||||
|
onResetState,
|
||||||
handleActionSave,
|
handleActionSave,
|
||||||
handleActionEdit,
|
handleActionEdit,
|
||||||
handleActionRemove,
|
handleActionRemove,
|
||||||
@@ -48,6 +49,7 @@ const {
|
|||||||
fetchFn: async (params: any) => {
|
fetchFn: async (params: any) => {
|
||||||
const result = await getList({
|
const result = await getList({
|
||||||
search: params.search,
|
search: params.search,
|
||||||
|
sort: 'createdAt:asc',
|
||||||
'page-number': params['page-number'] || 0,
|
'page-number': params['page-number'] || 0,
|
||||||
'page-size': params['page-size'] || 10,
|
'page-size': params['page-size'] || 10,
|
||||||
includes: 'installation',
|
includes: 'installation',
|
||||||
@@ -130,9 +132,24 @@ onMounted(async () => {
|
|||||||
@search="handleSearch"
|
@search="handleSearch"
|
||||||
class="mb-4 xl:mb-5"
|
class="mb-4 xl:mb-5"
|
||||||
/>
|
/>
|
||||||
<AppUnitList :data="data" :pagination-meta="paginationMeta" @page-change="handlePageChange" />
|
<AppUnitList
|
||||||
|
:data="data"
|
||||||
|
:pagination-meta="paginationMeta"
|
||||||
|
@page-change="handlePageChange"
|
||||||
|
/>
|
||||||
|
|
||||||
<Dialog v-model:open="isFormEntryDialogOpen" :title="!!recItem ? title : 'Tambah Unit'" size="lg" prevent-outside>
|
<Dialog
|
||||||
|
v-model:open="isFormEntryDialogOpen"
|
||||||
|
:title="!!recItem ? title : 'Tambah Unit'"
|
||||||
|
size="lg"
|
||||||
|
prevent-outside
|
||||||
|
@update:open="
|
||||||
|
(value: any) => {
|
||||||
|
onResetState()
|
||||||
|
isFormEntryDialogOpen = value
|
||||||
|
}
|
||||||
|
"
|
||||||
|
>
|
||||||
<AppUnitEntryForm
|
<AppUnitEntryForm
|
||||||
:schema="UnitSchema"
|
:schema="UnitSchema"
|
||||||
:installations="installations"
|
:installations="installations"
|
||||||
@@ -162,9 +179,18 @@ onMounted(async () => {
|
|||||||
>
|
>
|
||||||
<template #default="{ record }">
|
<template #default="{ record }">
|
||||||
<div class="text-sm">
|
<div class="text-sm">
|
||||||
<p><strong>ID:</strong> {{ record?.id }}</p>
|
<p>
|
||||||
<p v-if="record?.name"><strong>Nama:</strong> {{ record.name }}</p>
|
<strong>ID:</strong>
|
||||||
<p v-if="record?.code"><strong>Kode:</strong> {{ record.code }}</p>
|
{{ record?.id }}
|
||||||
|
</p>
|
||||||
|
<p v-if="record?.name">
|
||||||
|
<strong>Nama:</strong>
|
||||||
|
{{ record.name }}
|
||||||
|
</p>
|
||||||
|
<p v-if="record?.code">
|
||||||
|
<strong>Kode:</strong>
|
||||||
|
{{ record.code }}
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</RecordConfirmation>
|
</RecordConfirmation>
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ import {
|
|||||||
isProcessing,
|
isProcessing,
|
||||||
isFormEntryDialogOpen,
|
isFormEntryDialogOpen,
|
||||||
isRecordConfirmationOpen,
|
isRecordConfirmationOpen,
|
||||||
|
onResetState,
|
||||||
handleActionSave,
|
handleActionSave,
|
||||||
handleActionEdit,
|
handleActionEdit,
|
||||||
handleActionRemove,
|
handleActionRemove,
|
||||||
@@ -45,6 +46,7 @@ const {
|
|||||||
fetchFn: async (params: any) => {
|
fetchFn: async (params: any) => {
|
||||||
const result = await getList({
|
const result = await getList({
|
||||||
search: params.search,
|
search: params.search,
|
||||||
|
sort: 'createdAt:asc',
|
||||||
'page-number': params['page-number'] || 0,
|
'page-number': params['page-number'] || 0,
|
||||||
'page-size': params['page-size'] || 10,
|
'page-size': params['page-size'] || 10,
|
||||||
})
|
})
|
||||||
@@ -127,10 +129,25 @@ onMounted(async () => {
|
|||||||
class="mb-4 xl:mb-5"
|
class="mb-4 xl:mb-5"
|
||||||
/>
|
/>
|
||||||
<div class="rounded-md border p-4">
|
<div class="rounded-md border p-4">
|
||||||
<AppUomList :data="data" :pagination-meta="paginationMeta" @page-change="handlePageChange" />
|
<AppUomList
|
||||||
|
:data="data"
|
||||||
|
:pagination-meta="paginationMeta"
|
||||||
|
@page-change="handlePageChange"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<Dialog v-model:open="isFormEntryDialogOpen" :title="!!recItem ? title : 'Tambah Uom'" size="lg" prevent-outside>
|
<Dialog
|
||||||
|
v-model:open="isFormEntryDialogOpen"
|
||||||
|
:title="!!recItem ? title : 'Tambah Uom'"
|
||||||
|
size="lg"
|
||||||
|
prevent-outside
|
||||||
|
@update:open="
|
||||||
|
(value: any) => {
|
||||||
|
onResetState()
|
||||||
|
isFormEntryDialogOpen = value
|
||||||
|
}
|
||||||
|
"
|
||||||
|
>
|
||||||
<AppUomEntryForm
|
<AppUomEntryForm
|
||||||
:schema="UomSchema"
|
:schema="UomSchema"
|
||||||
:values="recItem"
|
:values="recItem"
|
||||||
@@ -159,9 +176,18 @@ onMounted(async () => {
|
|||||||
>
|
>
|
||||||
<template #default="{ record }">
|
<template #default="{ record }">
|
||||||
<div class="text-sm">
|
<div class="text-sm">
|
||||||
<p><strong>ID:</strong> {{ record?.id }}</p>
|
<p>
|
||||||
<p v-if="record?.name"><strong>Nama:</strong> {{ record.name }}</p>
|
<strong>ID:</strong>
|
||||||
<p v-if="record?.code"><strong>Kode:</strong> {{ record.code }}</p>
|
{{ record?.id }}
|
||||||
|
</p>
|
||||||
|
<p v-if="record?.name">
|
||||||
|
<strong>Nama:</strong>
|
||||||
|
{{ record.name }}
|
||||||
|
</p>
|
||||||
|
<p v-if="record?.code">
|
||||||
|
<strong>Kode:</strong>
|
||||||
|
{{ record.code }}
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</RecordConfirmation>
|
</RecordConfirmation>
|
||||||
|
|||||||
@@ -1,8 +1,198 @@
|
|||||||
<!-- Duplicated from content/counter/list.vue for warehouse -->
|
|
||||||
<!-- TODO: Update logic and fields for warehouse context -->
|
|
||||||
<template>
|
|
||||||
...existing code...
|
|
||||||
</template>
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
// ...existing code...
|
// Components
|
||||||
|
import Dialog from '~/components/pub/my-ui/modal/dialog.vue'
|
||||||
|
import Header from '~/components/pub/my-ui/nav-header/prep.vue'
|
||||||
|
import AppWarehouseList from '~/components/app/warehouse/list.vue'
|
||||||
|
import AppWarehouseEntryForm from '~/components/app/warehouse/entry-form.vue'
|
||||||
|
import RecordConfirmation from '~/components/pub/my-ui/confirmation/record-confirmation.vue'
|
||||||
|
|
||||||
|
// Constants
|
||||||
|
import { infraGroupCodesKeys } from '~/lib/constants'
|
||||||
|
|
||||||
|
// Helpers
|
||||||
|
import { usePaginatedList } from '~/composables/usePaginatedList'
|
||||||
|
import { toast } from '~/components/pub/ui/toast'
|
||||||
|
|
||||||
|
// Types
|
||||||
|
import { ActionEvents, type HeaderPrep } from '~/components/pub/my-ui/data/types'
|
||||||
|
import { InfraSchema, type InfraFormData } from '~/schemas/infra.schema'
|
||||||
|
|
||||||
|
// Handlers
|
||||||
|
import {
|
||||||
|
recId,
|
||||||
|
recAction,
|
||||||
|
recItem,
|
||||||
|
isReadonly,
|
||||||
|
isProcessing,
|
||||||
|
isFormEntryDialogOpen,
|
||||||
|
isRecordConfirmationOpen,
|
||||||
|
onResetState,
|
||||||
|
handleActionSave,
|
||||||
|
handleActionEdit,
|
||||||
|
handleActionRemove,
|
||||||
|
handleCancelForm,
|
||||||
|
} from '~/handlers/infra.handler'
|
||||||
|
|
||||||
|
// Services
|
||||||
|
import { getList, getDetail, getValueLabelList } from '~/services/infra.service'
|
||||||
|
|
||||||
|
const parents = ref<{ value: string | number; label: string }[]>([])
|
||||||
|
const title = ref('')
|
||||||
|
|
||||||
|
const {
|
||||||
|
data,
|
||||||
|
isLoading,
|
||||||
|
paginationMeta,
|
||||||
|
searchInput,
|
||||||
|
handlePageChange,
|
||||||
|
handleSearch,
|
||||||
|
fetchData: getItemList,
|
||||||
|
} = usePaginatedList({
|
||||||
|
fetchFn: async (params: any) => {
|
||||||
|
const result = await getList({
|
||||||
|
search: params.search,
|
||||||
|
sort: 'createdAt:asc',
|
||||||
|
'page-number': params['page-number'] || 2,
|
||||||
|
'page-size': params['page-size'] || 10,
|
||||||
|
'infraGroup-code': infraGroupCodesKeys.warehouse,
|
||||||
|
includes: 'parent',
|
||||||
|
})
|
||||||
|
return { success: result.success || false, body: result.body || {} }
|
||||||
|
},
|
||||||
|
entityName: 'warehouse',
|
||||||
|
})
|
||||||
|
|
||||||
|
const headerPrep: HeaderPrep = {
|
||||||
|
title: 'Gudang',
|
||||||
|
icon: 'i-lucide-layout-list',
|
||||||
|
refSearchNav: {
|
||||||
|
placeholder: 'Cari (min. 3 karakter)...',
|
||||||
|
minLength: 3,
|
||||||
|
debounceMs: 500,
|
||||||
|
showValidationFeedback: true,
|
||||||
|
onInput: (val: string) => {
|
||||||
|
searchInput.value = val
|
||||||
|
},
|
||||||
|
onClick: () => {},
|
||||||
|
onClear: () => {},
|
||||||
|
},
|
||||||
|
addNav: {
|
||||||
|
label: 'Tambah',
|
||||||
|
icon: 'i-lucide-plus',
|
||||||
|
onClick: () => {
|
||||||
|
recItem.value = null
|
||||||
|
recId.value = 0
|
||||||
|
isFormEntryDialogOpen.value = true
|
||||||
|
isReadonly.value = false
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
provide('rec_id', recId)
|
||||||
|
provide('rec_action', recAction)
|
||||||
|
provide('rec_item', recItem)
|
||||||
|
provide('table_data_loader', isLoading)
|
||||||
|
|
||||||
|
const getCurrentDetail = async (id: number | string) => {
|
||||||
|
const result = await getDetail(id)
|
||||||
|
if (result.success) {
|
||||||
|
const currentValue = result.body?.data || {}
|
||||||
|
recItem.value = currentValue
|
||||||
|
isFormEntryDialogOpen.value = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
watch([recId, recAction], () => {
|
||||||
|
switch (recAction.value) {
|
||||||
|
case ActionEvents.showDetail:
|
||||||
|
getCurrentDetail(recId.value)
|
||||||
|
title.value = 'Detail Gudang'
|
||||||
|
isReadonly.value = true
|
||||||
|
break
|
||||||
|
case ActionEvents.showEdit:
|
||||||
|
getCurrentDetail(recId.value)
|
||||||
|
title.value = 'Edit Gudang'
|
||||||
|
isReadonly.value = false
|
||||||
|
break
|
||||||
|
case ActionEvents.showConfirmDelete:
|
||||||
|
isRecordConfirmationOpen.value = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
onMounted(async () => {
|
||||||
|
parents.value = await getValueLabelList({ sort: 'createdAt:asc', 'infraGroup-code': infraGroupCodesKeys.floor })
|
||||||
|
await getItemList()
|
||||||
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<Header
|
||||||
|
v-model="searchInput"
|
||||||
|
:prep="headerPrep"
|
||||||
|
:ref-search-nav="headerPrep.refSearchNav"
|
||||||
|
@search="handleSearch"
|
||||||
|
class="mb-4 xl:mb-5"
|
||||||
|
/>
|
||||||
|
<AppWarehouseList
|
||||||
|
:data="data"
|
||||||
|
:pagination-meta="paginationMeta"
|
||||||
|
@page-change="handlePageChange"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<Dialog
|
||||||
|
v-model:open="isFormEntryDialogOpen"
|
||||||
|
:title="!!recItem ? title : 'Tambah Gudang'"
|
||||||
|
size="lg"
|
||||||
|
prevent-outside
|
||||||
|
@update:open="
|
||||||
|
(value: any) => {
|
||||||
|
onResetState()
|
||||||
|
isFormEntryDialogOpen = value
|
||||||
|
}
|
||||||
|
"
|
||||||
|
>
|
||||||
|
<AppWarehouseEntryForm
|
||||||
|
:schema="InfraSchema"
|
||||||
|
:parents="parents"
|
||||||
|
:values="recItem"
|
||||||
|
:is-loading="isProcessing"
|
||||||
|
:is-readonly="isReadonly"
|
||||||
|
@submit="
|
||||||
|
(values: InfraFormData | Record<string, any>, resetForm: () => void) => {
|
||||||
|
if (recId > 0) {
|
||||||
|
handleActionEdit(recId, values, getItemList, resetForm, toast)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
handleActionSave(values, getItemList, resetForm, toast)
|
||||||
|
}
|
||||||
|
"
|
||||||
|
@cancel="handleCancelForm"
|
||||||
|
/>
|
||||||
|
</Dialog>
|
||||||
|
|
||||||
|
<RecordConfirmation
|
||||||
|
v-model:open="isRecordConfirmationOpen"
|
||||||
|
action="delete"
|
||||||
|
:record="recItem"
|
||||||
|
@confirm="() => handleActionRemove(recId, getItemList, toast)"
|
||||||
|
@cancel=""
|
||||||
|
>
|
||||||
|
<template #default="{ record }">
|
||||||
|
<div class="text-sm">
|
||||||
|
<p>
|
||||||
|
<strong>ID:</strong>
|
||||||
|
{{ record?.id }}
|
||||||
|
</p>
|
||||||
|
<p v-if="record?.name">
|
||||||
|
<strong>Nama:</strong>
|
||||||
|
{{ record.name }}
|
||||||
|
</p>
|
||||||
|
<p v-if="record?.code">
|
||||||
|
<strong>Kode:</strong>
|
||||||
|
{{ record.code }}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</RecordConfirmation>
|
||||||
|
</template>
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ const openCollapsible = ref(false)
|
|||||||
<Collapsible :key="item.title" v-model:open="openCollapsible" as-child class="group/collapsible ">
|
<Collapsible :key="item.title" v-model:open="openCollapsible" as-child class="group/collapsible ">
|
||||||
<SidebarMenuItem>
|
<SidebarMenuItem>
|
||||||
<CollapsibleTrigger as-child>
|
<CollapsibleTrigger as-child>
|
||||||
<SidebarMenuButton :tooltip="item.title" :size="size" class="md:!text-xs xl:!text-sm 2xl:!text-base">
|
<SidebarMenuButton :tooltip="item.title" :size="size" class="md:!text-xs 2xl:!text-sm">
|
||||||
<Icon :name="item.icon || ''" mode="svg" />
|
<Icon :name="item.icon || ''" mode="svg" />
|
||||||
<span class="mx-2">{{ item.title }}</span>
|
<span class="mx-2">{{ item.title }}</span>
|
||||||
<Icon
|
<Icon
|
||||||
@@ -37,7 +37,7 @@ const openCollapsible = ref(false)
|
|||||||
<SidebarMenuSubButton as-child>
|
<SidebarMenuSubButton as-child>
|
||||||
<NuxtLink
|
<NuxtLink
|
||||||
:to="subItem.link"
|
:to="subItem.link"
|
||||||
class="mx-4 rounded-lg py-5 text-sm transition-all duration-200 md:!text-xs xl:!text-sm 2xl:!text-base"
|
class="mx-4 rounded-lg py-2 2xl:py-2.5 text-sm transition-all duration-200 md:!text-xs 2xl:!text-sm 2xl:!text-base"
|
||||||
active-class="bg-primary text-white"
|
active-class="bg-primary text-white"
|
||||||
@click="setOpenMobile(false)"
|
@click="setOpenMobile(false)"
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -22,13 +22,13 @@ const activeTeam = ref(props.teams[0])
|
|||||||
<div
|
<div
|
||||||
class="bg-sidebar-primary text-sidebar-primary-foreground flex aspect-square size-8 items-center justify-center rounded-lg"
|
class="bg-sidebar-primary text-sidebar-primary-foreground flex aspect-square size-8 items-center justify-center rounded-lg"
|
||||||
>
|
>
|
||||||
<img :src="activeTeam.logo" class="h-full w-full" />
|
<img :src="activeTeam?.logo" class="h-full w-full" />
|
||||||
</div>
|
</div>
|
||||||
<div class="grid flex-1 text-left text-sm leading-tight">
|
<div class="grid flex-1 text-left text-sm leading-tight">
|
||||||
<span class="truncate font-semibold">
|
<span class="truncate font-semibold">
|
||||||
{{ activeTeam.name }}
|
{{ activeTeam?.name }}
|
||||||
</span>
|
</span>
|
||||||
<span class="truncate text-xs">{{ activeTeam.plan }}</span>
|
<span class="truncate text-xs">{{ activeTeam?.plan }}</span>
|
||||||
</div>
|
</div>
|
||||||
</SidebarMenuButton>
|
</SidebarMenuButton>
|
||||||
</DropdownMenuTrigger>
|
</DropdownMenuTrigger>
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ const { setOpenMobile } = useSidebar()
|
|||||||
<SidebarMenuButton as-child :tooltip="item.title" :size="size" class="">
|
<SidebarMenuButton as-child :tooltip="item.title" :size="size" class="">
|
||||||
<NuxtLink
|
<NuxtLink
|
||||||
:to="item.link"
|
:to="item.link"
|
||||||
class="group flex items-center gap-3 rounded-lg px-2 py-4 text-sm transition-all duration-200 md:!text-xs xl:!text-sm 2xl:!text-base"
|
class="group flex items-center gap-3 rounded-lg px-2 py-2 2xl:py-2.5 text-sm transition-all duration-200 md:!text-xs 2xl:!text-sm"
|
||||||
active-class="bg-primary text-white"
|
active-class="bg-primary text-white"
|
||||||
@click="setOpenMobile(false)"
|
@click="setOpenMobile(false)"
|
||||||
>
|
>
|
||||||
|
|||||||
+10
-10
@@ -1,15 +1,10 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { cn } from '~/lib/utils'
|
import { cn } from '~/lib/utils'
|
||||||
|
|
||||||
interface Item {
|
import { type Item } from './index'
|
||||||
value: string
|
|
||||||
label: string
|
|
||||||
code?: string
|
|
||||||
priority?: number
|
|
||||||
}
|
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
id: string
|
id?: string
|
||||||
modelValue?: string
|
modelValue?: string
|
||||||
items: Item[]
|
items: Item[]
|
||||||
placeholder?: string
|
placeholder?: string
|
||||||
@@ -28,12 +23,17 @@ const open = ref(false)
|
|||||||
const selectedItem = computed(() => props.items.find((item) => item.value === props.modelValue))
|
const selectedItem = computed(() => props.items.find((item) => item.value === props.modelValue))
|
||||||
|
|
||||||
const displayText = computed(() => {
|
const displayText = computed(() => {
|
||||||
|
console.log(selectedItem);
|
||||||
if (selectedItem.value?.label) {
|
if (selectedItem.value?.label) {
|
||||||
return selectedItem.value.label
|
return selectedItem.value.label
|
||||||
}
|
}
|
||||||
return props.placeholder || 'Pilih item'
|
return props.placeholder || 'Pilih item'
|
||||||
})
|
})
|
||||||
|
|
||||||
|
watch(props, () => {
|
||||||
|
console.log(props.modelValue);
|
||||||
|
})
|
||||||
|
|
||||||
const searchableItems = computed(() => {
|
const searchableItems = computed(() => {
|
||||||
const itemsWithSearch = props.items.map((item) => ({
|
const itemsWithSearch = props.items.map((item) => ({
|
||||||
...item,
|
...item,
|
||||||
@@ -74,10 +74,10 @@ function onSelect(item: Item) {
|
|||||||
:aria-describedby="`${props.id}-search`"
|
:aria-describedby="`${props.id}-search`"
|
||||||
:class="
|
:class="
|
||||||
cn(
|
cn(
|
||||||
'w-full justify-between border text-sm font-normal rounded-md px-3 py-2 focus:outline-none focus:ring-1 focus:ring-black dark:focus:ring-white',
|
'w-full justify-between border dark:!border-slate-400 h-8 2xl:h-9 md:text-xs 2xl:text-sm font-normal rounded-md px-3 focus:outline-none focus:ring-1 focus:ring-black dark:focus:ring-white',
|
||||||
{
|
{
|
||||||
'cursor-not-allowed bg-gray-100 opacity-50 border-gray-300 text-gray-500': props.isDisabled,
|
'cursor-not-allowed bg-gray-100 opacity-50 border-gray-300 text-gray-500': props.isDisabled,
|
||||||
'bg-white text-black dark:bg-gray-800 dark:text-white dark:border-gray-600 border-gray-400 hover:bg-gray-50 dark:hover:bg-gray-700': !props.isDisabled,
|
'bg-white text-black dark:bg-slate-950 dark:text-white dark:border-gray-600 border-gray-400 hover:bg-gray-50 dark:hover:bg-gray-700': !props.isDisabled,
|
||||||
'text-gray-400 dark:text-gray-500': !modelValue && !props.isDisabled,
|
'text-gray-400 dark:text-gray-500': !modelValue && !props.isDisabled,
|
||||||
},
|
},
|
||||||
props.class,
|
props.class,
|
||||||
@@ -117,7 +117,7 @@ function onSelect(item: Item) {
|
|||||||
:value="item.searchValue"
|
:value="item.searchValue"
|
||||||
:class="
|
:class="
|
||||||
cn(
|
cn(
|
||||||
'flex w-full cursor-pointer items-center justify-between rounded-sm px-2 py-1.5 text-sm',
|
'flex w-full cursor-pointer items-center justify-between rounded-sm px-2 py-1.5 md:text-xs xl:text-sm',
|
||||||
'focus:outline-none text-black dark:text-white',
|
'focus:outline-none text-black dark:text-white',
|
||||||
'hover:bg-primary hover:text-white focus:bg-primary focus:text-white',
|
'hover:bg-primary hover:text-white focus:bg-primary focus:text-white',
|
||||||
'data-[highlighted]:bg-primary data-[highlighted]:text-white',
|
'data-[highlighted]:bg-primary data-[highlighted]:text-white',
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
export interface Item {
|
||||||
|
value: string
|
||||||
|
label: string
|
||||||
|
code?: string
|
||||||
|
priority?: number
|
||||||
|
}
|
||||||
|
|
||||||
|
export function recStrToItem(input: Record<string, string>): Item[] {
|
||||||
|
const items: Item[] = []
|
||||||
|
let idx = 0;
|
||||||
|
for (const key in input) {
|
||||||
|
if (input.hasOwnProperty(key)) {
|
||||||
|
items.push({
|
||||||
|
value: key || ('unknown-' + idx),
|
||||||
|
label: input[key] || ('unknown-' + idx),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
idx++
|
||||||
|
}
|
||||||
|
return items
|
||||||
|
}
|
||||||
|
|
||||||
|
export { default as Combobox } from './combobox.vue'
|
||||||
@@ -19,7 +19,7 @@ function changeTab(value: string) {
|
|||||||
|
|
||||||
<template>
|
<template>
|
||||||
<!-- Tabs -->
|
<!-- Tabs -->
|
||||||
<div class="mt-4 flex flex-wrap gap-2 rounded-md border bg-white p-4 shadow-sm">
|
<div class="mt-4 flex flex-wrap gap-2 rounded-md border bg-white dark:bg-neutral-950 p-4 shadow-sm">
|
||||||
<Button
|
<Button
|
||||||
v-for="tab in data"
|
v-for="tab in data"
|
||||||
:key="tab.value"
|
:key="tab.value"
|
||||||
|
|||||||
@@ -9,19 +9,7 @@ const props = defineProps<{
|
|||||||
const recId = inject<Ref<number>>('rec_id')!
|
const recId = inject<Ref<number>>('rec_id')!
|
||||||
const recAction = inject<Ref<string>>('rec_action')!
|
const recAction = inject<Ref<string>>('rec_action')!
|
||||||
const recItem = inject<Ref<any>>('rec_item')!
|
const recItem = inject<Ref<any>>('rec_item')!
|
||||||
|
const activeKey = ref<string | null>(null)
|
||||||
function detail() {
|
|
||||||
recId.value = props.rec.id || 0
|
|
||||||
recAction.value = ActionEvents.showDetail
|
|
||||||
recItem.value = props.rec
|
|
||||||
}
|
|
||||||
|
|
||||||
function edit() {
|
|
||||||
recId.value = props.rec.id || 0
|
|
||||||
recAction.value = ActionEvents.showEdit
|
|
||||||
recItem.value = props.rec
|
|
||||||
}
|
|
||||||
|
|
||||||
const linkItems: LinkItem[] = [
|
const linkItems: LinkItem[] = [
|
||||||
{
|
{
|
||||||
label: 'Detail',
|
label: 'Detail',
|
||||||
@@ -38,6 +26,18 @@ const linkItems: LinkItem[] = [
|
|||||||
icon: 'i-lucide-pencil',
|
icon: 'i-lucide-pencil',
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
|
|
||||||
|
function detail() {
|
||||||
|
recId.value = props.rec.id || 0
|
||||||
|
recAction.value = ActionEvents.showDetail
|
||||||
|
recItem.value = props.rec
|
||||||
|
}
|
||||||
|
|
||||||
|
function edit() {
|
||||||
|
recId.value = props.rec.id || 0
|
||||||
|
recAction.value = ActionEvents.showEdit
|
||||||
|
recItem.value = props.rec
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
@@ -46,22 +46,29 @@ const linkItems: LinkItem[] = [
|
|||||||
<DropdownMenuTrigger as-child>
|
<DropdownMenuTrigger as-child>
|
||||||
<SidebarMenuButton
|
<SidebarMenuButton
|
||||||
size="lg"
|
size="lg"
|
||||||
class="data-[state=open]:text-sidebar-accent-foreground data-[state=open]:bg-white"
|
class="data-[state=open]:text-sidebar-accent-foreground data-[state=open]:bg-white dark:data-[state=open]:bg-slate-800"
|
||||||
>
|
>
|
||||||
<Icon name="i-lucide-chevrons-up-down" class="ml-auto size-4" />
|
<Icon
|
||||||
|
name="i-lucide-chevrons-up-down"
|
||||||
|
class="ml-auto size-4"
|
||||||
|
/>
|
||||||
</SidebarMenuButton>
|
</SidebarMenuButton>
|
||||||
</DropdownMenuTrigger>
|
</DropdownMenuTrigger>
|
||||||
<DropdownMenuContent class="w-[--radix-dropdown-menu-trigger-width] min-w-40 rounded-lg bg-white" align="end">
|
<DropdownMenuContent
|
||||||
|
class="w-[--radix-dropdown-menu-trigger-width] min-w-40 rounded-lg border border-slate-200 bg-white text-black dark:border-slate-700 dark:bg-slate-800 dark:text-white"
|
||||||
|
align="end"
|
||||||
|
>
|
||||||
<DropdownMenuGroup>
|
<DropdownMenuGroup>
|
||||||
<DropdownMenuItem
|
<DropdownMenuItem
|
||||||
v-for="item in linkItems"
|
v-for="item in linkItems"
|
||||||
:key="item.label"
|
:key="item.label"
|
||||||
v-slot="{ active }"
|
class="hover:bg-gray-100 dark:hover:bg-slate-700"
|
||||||
class="hover:bg-gray-100"
|
|
||||||
@click="item.onClick"
|
@click="item.onClick"
|
||||||
|
@mouseenter="activeKey = item.label"
|
||||||
|
@mouseleave="activeKey = null"
|
||||||
>
|
>
|
||||||
<Icon :name="item.icon" />
|
<Icon :name="item.icon ?? ''" />
|
||||||
<span :class="active ? 'text-sidebar-accent-foreground' : ''">{{ item.label }}</span>
|
<span :class="activeKey === item.label ? 'text-sidebar-accent-foreground' : ''">{{ item.label }}</span>
|
||||||
</DropdownMenuItem>
|
</DropdownMenuItem>
|
||||||
</DropdownMenuGroup>
|
</DropdownMenuGroup>
|
||||||
</DropdownMenuContent>
|
</DropdownMenuContent>
|
||||||
|
|||||||
@@ -9,25 +9,7 @@ const props = defineProps<{
|
|||||||
const recId = inject<Ref<number>>('rec_id')!
|
const recId = inject<Ref<number>>('rec_id')!
|
||||||
const recAction = inject<Ref<string>>('rec_action')!
|
const recAction = inject<Ref<string>>('rec_action')!
|
||||||
const recItem = inject<Ref<any>>('rec_item')!
|
const recItem = inject<Ref<any>>('rec_item')!
|
||||||
|
const activeKey = ref<string | null>(null)
|
||||||
function detail() {
|
|
||||||
recId.value = props.rec.id || 0
|
|
||||||
recAction.value = ActionEvents.showDetail
|
|
||||||
recItem.value = props.rec
|
|
||||||
}
|
|
||||||
|
|
||||||
function edit() {
|
|
||||||
recId.value = props.rec.id || 0
|
|
||||||
recAction.value = ActionEvents.showEdit
|
|
||||||
recItem.value = props.rec
|
|
||||||
}
|
|
||||||
|
|
||||||
function del() {
|
|
||||||
recId.value = props.rec.id || 0
|
|
||||||
recAction.value = ActionEvents.showConfirmDelete
|
|
||||||
recItem.value = props.rec
|
|
||||||
}
|
|
||||||
|
|
||||||
const linkItems: LinkItem[] = [
|
const linkItems: LinkItem[] = [
|
||||||
{
|
{
|
||||||
label: 'Detail',
|
label: 'Detail',
|
||||||
@@ -58,6 +40,24 @@ const linkItems: LinkItem[] = [
|
|||||||
icon: 'i-lucide-trash',
|
icon: 'i-lucide-trash',
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
|
|
||||||
|
function detail() {
|
||||||
|
recId.value = props.rec.id || 0
|
||||||
|
recAction.value = ActionEvents.showDetail
|
||||||
|
recItem.value = props.rec
|
||||||
|
}
|
||||||
|
|
||||||
|
function edit() {
|
||||||
|
recId.value = props.rec.id || 0
|
||||||
|
recAction.value = ActionEvents.showEdit
|
||||||
|
recItem.value = props.rec
|
||||||
|
}
|
||||||
|
|
||||||
|
function del() {
|
||||||
|
recId.value = props.rec.id || 0
|
||||||
|
recAction.value = ActionEvents.showConfirmDelete
|
||||||
|
recItem.value = props.rec
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
@@ -66,22 +66,29 @@ const linkItems: LinkItem[] = [
|
|||||||
<DropdownMenuTrigger as-child>
|
<DropdownMenuTrigger as-child>
|
||||||
<SidebarMenuButton
|
<SidebarMenuButton
|
||||||
size="lg"
|
size="lg"
|
||||||
class="data-[state=open]:text-sidebar-accent-foreground data-[state=open]:bg-white"
|
class="data-[state=open]:text-sidebar-accent-foreground data-[state=open]:bg-white dark:data-[state=open]:bg-slate-800"
|
||||||
>
|
>
|
||||||
<Icon name="i-lucide-chevrons-up-down" class="ml-auto size-4" />
|
<Icon
|
||||||
|
name="i-lucide-chevrons-up-down"
|
||||||
|
class="ml-auto size-4"
|
||||||
|
/>
|
||||||
</SidebarMenuButton>
|
</SidebarMenuButton>
|
||||||
</DropdownMenuTrigger>
|
</DropdownMenuTrigger>
|
||||||
<DropdownMenuContent class="w-[--radix-dropdown-menu-trigger-width] min-w-40 rounded-lg bg-white" align="end">
|
<DropdownMenuContent
|
||||||
|
class="w-[--radix-dropdown-menu-trigger-width] min-w-40 rounded-lg border border-slate-200 bg-white text-black dark:border-slate-700 dark:bg-slate-800 dark:text-white"
|
||||||
|
align="end"
|
||||||
|
>
|
||||||
<DropdownMenuGroup>
|
<DropdownMenuGroup>
|
||||||
<DropdownMenuItem
|
<DropdownMenuItem
|
||||||
v-for="item in linkItems"
|
v-for="item in linkItems"
|
||||||
:key="item.label"
|
:key="item.label"
|
||||||
v-slot="{ active }"
|
class="hover:bg-gray-100 dark:hover:bg-slate-700"
|
||||||
class="hover:bg-gray-100"
|
|
||||||
@click="item.onClick"
|
@click="item.onClick"
|
||||||
|
@mouseenter="activeKey = item.label"
|
||||||
|
@mouseleave="activeKey = null"
|
||||||
>
|
>
|
||||||
<Icon :name="item.icon" />
|
<Icon :name="item.icon ?? ''" />
|
||||||
<span :class="active ? 'text-sidebar-accent-foreground' : ''">{{ item.label }}</span>
|
<span :class="activeKey === item.label ? 'text-sidebar-accent-foreground' : ''">{{ item.label }}</span>
|
||||||
</DropdownMenuItem>
|
</DropdownMenuItem>
|
||||||
</DropdownMenuGroup>
|
</DropdownMenuGroup>
|
||||||
</DropdownMenuContent>
|
</DropdownMenuContent>
|
||||||
|
|||||||
@@ -9,25 +9,7 @@ const props = defineProps<{
|
|||||||
const recId = inject<Ref<number>>('rec_id')!
|
const recId = inject<Ref<number>>('rec_id')!
|
||||||
const recAction = inject<Ref<string>>('rec_action')!
|
const recAction = inject<Ref<string>>('rec_action')!
|
||||||
const recItem = inject<Ref<any>>('rec_item')!
|
const recItem = inject<Ref<any>>('rec_item')!
|
||||||
|
const activeKey = ref<string | null>(null)
|
||||||
function detail() {
|
|
||||||
recId.value = props.rec.id || 0
|
|
||||||
recAction.value = ActionEvents.showDetail
|
|
||||||
recItem.value = props.rec
|
|
||||||
}
|
|
||||||
|
|
||||||
function edit() {
|
|
||||||
recId.value = props.rec.id || 0
|
|
||||||
recAction.value = ActionEvents.showEdit
|
|
||||||
recItem.value = props.rec
|
|
||||||
}
|
|
||||||
|
|
||||||
function del() {
|
|
||||||
recId.value = props.rec.id || 0
|
|
||||||
recAction.value = ActionEvents.showConfirmDelete
|
|
||||||
recItem.value = props.rec
|
|
||||||
}
|
|
||||||
|
|
||||||
const linkItems: LinkItem[] = [
|
const linkItems: LinkItem[] = [
|
||||||
{
|
{
|
||||||
label: 'Detail',
|
label: 'Detail',
|
||||||
@@ -51,6 +33,24 @@ const linkItems: LinkItem[] = [
|
|||||||
icon: 'i-lucide-trash',
|
icon: 'i-lucide-trash',
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
|
|
||||||
|
function detail() {
|
||||||
|
recId.value = props.rec.id || 0
|
||||||
|
recAction.value = ActionEvents.showDetail
|
||||||
|
recItem.value = props.rec
|
||||||
|
}
|
||||||
|
|
||||||
|
function edit() {
|
||||||
|
recId.value = props.rec.id || 0
|
||||||
|
recAction.value = ActionEvents.showEdit
|
||||||
|
recItem.value = props.rec
|
||||||
|
}
|
||||||
|
|
||||||
|
function del() {
|
||||||
|
recId.value = props.rec.id || 0
|
||||||
|
recAction.value = ActionEvents.showConfirmDelete
|
||||||
|
recItem.value = props.rec
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
@@ -59,22 +59,29 @@ const linkItems: LinkItem[] = [
|
|||||||
<DropdownMenuTrigger as-child>
|
<DropdownMenuTrigger as-child>
|
||||||
<SidebarMenuButton
|
<SidebarMenuButton
|
||||||
size="lg"
|
size="lg"
|
||||||
class="data-[state=open]:text-sidebar-accent-foreground data-[state=open]:bg-white"
|
class="data-[state=open]:text-sidebar-accent-foreground data-[state=open]:bg-white dark:data-[state=open]:bg-slate-800"
|
||||||
>
|
>
|
||||||
<Icon name="i-lucide-chevrons-up-down" class="ml-auto size-4" />
|
<Icon
|
||||||
|
name="i-lucide-chevrons-up-down"
|
||||||
|
class="ml-auto size-4"
|
||||||
|
/>
|
||||||
</SidebarMenuButton>
|
</SidebarMenuButton>
|
||||||
</DropdownMenuTrigger>
|
</DropdownMenuTrigger>
|
||||||
<DropdownMenuContent class="w-[--radix-dropdown-menu-trigger-width] min-w-40 rounded-lg bg-white" align="end">
|
<DropdownMenuContent
|
||||||
|
class="w-[--radix-dropdown-menu-trigger-width] min-w-40 rounded-lg border border-slate-200 bg-white text-black dark:border-slate-700 dark:bg-slate-800 dark:text-white"
|
||||||
|
align="end"
|
||||||
|
>
|
||||||
<DropdownMenuGroup>
|
<DropdownMenuGroup>
|
||||||
<DropdownMenuItem
|
<DropdownMenuItem
|
||||||
v-for="item in linkItems"
|
v-for="item in linkItems"
|
||||||
:key="item.label"
|
:key="item.label"
|
||||||
v-slot="{ active }"
|
class="hover:bg-gray-100 dark:hover:bg-slate-700"
|
||||||
class="hover:bg-gray-100"
|
|
||||||
@click="item.onClick"
|
@click="item.onClick"
|
||||||
|
@mouseenter="activeKey = item.label"
|
||||||
|
@mouseleave="activeKey = null"
|
||||||
>
|
>
|
||||||
<Icon :name="item.icon" />
|
<Icon :name="item.icon ?? ''" />
|
||||||
<span :class="active ? 'text-sidebar-accent-foreground' : ''">{{ item.label }}</span>
|
<span :class="activeKey === item.label ? 'text-sidebar-accent-foreground' : ''">{{ item.label }}</span>
|
||||||
</DropdownMenuItem>
|
</DropdownMenuItem>
|
||||||
</DropdownMenuGroup>
|
</DropdownMenuGroup>
|
||||||
</DropdownMenuContent>
|
</DropdownMenuContent>
|
||||||
|
|||||||
@@ -9,31 +9,7 @@ const props = defineProps<{
|
|||||||
const recId = inject<Ref<number>>('rec_id')!
|
const recId = inject<Ref<number>>('rec_id')!
|
||||||
const recAction = inject<Ref<string>>('rec_action')!
|
const recAction = inject<Ref<string>>('rec_action')!
|
||||||
const recItem = inject<Ref<any>>('rec_item')!
|
const recItem = inject<Ref<any>>('rec_item')!
|
||||||
|
const activeKey = ref<string | null>(null)
|
||||||
function detail() {
|
|
||||||
recId.value = props.rec.id || 0
|
|
||||||
recAction.value = ActionEvents.showDetail
|
|
||||||
recItem.value = props.rec
|
|
||||||
}
|
|
||||||
|
|
||||||
function process() {
|
|
||||||
recId.value = props.rec.id || 0
|
|
||||||
recAction.value = ActionEvents.showProcess
|
|
||||||
recItem.value = props.rec
|
|
||||||
}
|
|
||||||
|
|
||||||
function edit() {
|
|
||||||
recId.value = props.rec.id || 0
|
|
||||||
recAction.value = ActionEvents.showEdit
|
|
||||||
recItem.value = props.rec
|
|
||||||
}
|
|
||||||
|
|
||||||
function del() {
|
|
||||||
recId.value = props.rec.id || 0
|
|
||||||
recAction.value = ActionEvents.showConfirmDelete
|
|
||||||
recItem.value = props.rec
|
|
||||||
}
|
|
||||||
|
|
||||||
const linkItems: LinkItem[] = [
|
const linkItems: LinkItem[] = [
|
||||||
{
|
{
|
||||||
label: 'Proses',
|
label: 'Proses',
|
||||||
@@ -64,6 +40,30 @@ const linkItems: LinkItem[] = [
|
|||||||
icon: 'i-lucide-trash',
|
icon: 'i-lucide-trash',
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
|
|
||||||
|
function detail() {
|
||||||
|
recId.value = props.rec.id || 0
|
||||||
|
recAction.value = ActionEvents.showDetail
|
||||||
|
recItem.value = props.rec
|
||||||
|
}
|
||||||
|
|
||||||
|
function process() {
|
||||||
|
recId.value = props.rec.id || 0
|
||||||
|
recAction.value = ActionEvents.showProcess
|
||||||
|
recItem.value = props.rec
|
||||||
|
}
|
||||||
|
|
||||||
|
function edit() {
|
||||||
|
recId.value = props.rec.id || 0
|
||||||
|
recAction.value = ActionEvents.showEdit
|
||||||
|
recItem.value = props.rec
|
||||||
|
}
|
||||||
|
|
||||||
|
function del() {
|
||||||
|
recId.value = props.rec.id || 0
|
||||||
|
recAction.value = ActionEvents.showConfirmDelete
|
||||||
|
recItem.value = props.rec
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
@@ -72,22 +72,29 @@ const linkItems: LinkItem[] = [
|
|||||||
<DropdownMenuTrigger as-child>
|
<DropdownMenuTrigger as-child>
|
||||||
<SidebarMenuButton
|
<SidebarMenuButton
|
||||||
size="lg"
|
size="lg"
|
||||||
class="data-[state=open]:text-sidebar-accent-foreground data-[state=open]:bg-white"
|
class="data-[state=open]:text-sidebar-accent-foreground data-[state=open]:bg-white dark:data-[state=open]:bg-slate-800"
|
||||||
>
|
>
|
||||||
<Icon name="i-lucide-chevrons-up-down" class="ml-auto size-4" />
|
<Icon
|
||||||
|
name="i-lucide-chevrons-up-down"
|
||||||
|
class="ml-auto size-4"
|
||||||
|
/>
|
||||||
</SidebarMenuButton>
|
</SidebarMenuButton>
|
||||||
</DropdownMenuTrigger>
|
</DropdownMenuTrigger>
|
||||||
<DropdownMenuContent class="w-[--radix-dropdown-menu-trigger-width] min-w-40 rounded-lg bg-white" align="end">
|
<DropdownMenuContent
|
||||||
|
class="w-[--radix-dropdown-menu-trigger-width] min-w-40 rounded-lg border border-slate-200 bg-white text-black dark:border-slate-700 dark:bg-slate-800 dark:text-white"
|
||||||
|
align="end"
|
||||||
|
>
|
||||||
<DropdownMenuGroup>
|
<DropdownMenuGroup>
|
||||||
<DropdownMenuItem
|
<DropdownMenuItem
|
||||||
v-for="item in linkItems"
|
v-for="item in linkItems"
|
||||||
:key="item.label"
|
:key="item.label"
|
||||||
v-slot="{ active }"
|
class="hover:bg-gray-100 dark:hover:bg-slate-700"
|
||||||
class="hover:bg-gray-100"
|
|
||||||
@click="item.onClick"
|
@click="item.onClick"
|
||||||
|
@mouseenter="activeKey = item.label"
|
||||||
|
@mouseleave="activeKey = null"
|
||||||
>
|
>
|
||||||
<Icon :name="item.icon" />
|
<Icon :name="item.icon ?? ''" />
|
||||||
<span :class="active ? 'text-sidebar-accent-foreground' : ''">{{ item.label }}</span>
|
<span :class="activeKey === item.label ? 'text-sidebar-accent-foreground' : ''">{{ item.label }}</span>
|
||||||
</DropdownMenuItem>
|
</DropdownMenuItem>
|
||||||
</DropdownMenuGroup>
|
</DropdownMenuGroup>
|
||||||
</DropdownMenuContent>
|
</DropdownMenuContent>
|
||||||
|
|||||||
@@ -14,19 +14,7 @@ const props = withDefaults(defineProps<Props>(), {
|
|||||||
const recId = inject<Ref<number>>('rec_id')!
|
const recId = inject<Ref<number>>('rec_id')!
|
||||||
const recAction = inject<Ref<string>>('rec_action')!
|
const recAction = inject<Ref<string>>('rec_action')!
|
||||||
const recItem = inject<Ref<any>>('rec_item')!
|
const recItem = inject<Ref<any>>('rec_item')!
|
||||||
|
const activeKey = ref<string | null>(null)
|
||||||
function edit() {
|
|
||||||
recId.value = props.rec.id || 0
|
|
||||||
recAction.value = ActionEvents.showEdit
|
|
||||||
recItem.value = props.rec
|
|
||||||
}
|
|
||||||
|
|
||||||
function del() {
|
|
||||||
recId.value = props.rec.id || 0
|
|
||||||
recAction.value = ActionEvents.showConfirmDelete
|
|
||||||
recItem.value = props.rec
|
|
||||||
}
|
|
||||||
|
|
||||||
const linkItems: LinkItem[] = [
|
const linkItems: LinkItem[] = [
|
||||||
{
|
{
|
||||||
label: 'Edit',
|
label: 'Edit',
|
||||||
@@ -43,6 +31,18 @@ const linkItems: LinkItem[] = [
|
|||||||
icon: 'i-lucide-trash',
|
icon: 'i-lucide-trash',
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
|
|
||||||
|
function edit() {
|
||||||
|
recId.value = props.rec.id || 0
|
||||||
|
recAction.value = ActionEvents.showEdit
|
||||||
|
recItem.value = props.rec
|
||||||
|
}
|
||||||
|
|
||||||
|
function del() {
|
||||||
|
recId.value = props.rec.id || 0
|
||||||
|
recAction.value = ActionEvents.showConfirmDelete
|
||||||
|
recItem.value = props.rec
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
@@ -51,22 +51,29 @@ const linkItems: LinkItem[] = [
|
|||||||
<DropdownMenuTrigger as-child>
|
<DropdownMenuTrigger as-child>
|
||||||
<SidebarMenuButton
|
<SidebarMenuButton
|
||||||
:size="size"
|
:size="size"
|
||||||
class="data-[state=open]:text-sidebar-accent-foreground data-[state=open]:bg-white"
|
class="data-[state=open]:text-sidebar-accent-foreground data-[state=open]:bg-white dark:data-[state=open]:bg-slate-800"
|
||||||
>
|
>
|
||||||
<Icon name="i-lucide-chevrons-up-down" class="ml-auto size-4" />
|
<Icon
|
||||||
|
name="i-lucide-chevrons-up-down"
|
||||||
|
class="ml-auto size-4"
|
||||||
|
/>
|
||||||
</SidebarMenuButton>
|
</SidebarMenuButton>
|
||||||
</DropdownMenuTrigger>
|
</DropdownMenuTrigger>
|
||||||
<DropdownMenuContent class="w-[--radix-dropdown-menu-trigger-width] min-w-40 rounded-lg bg-white" align="end">
|
<DropdownMenuContent
|
||||||
|
class="w-[--radix-dropdown-menu-trigger-width] min-w-40 rounded-lg border border-slate-200 bg-white text-black dark:border-slate-700 dark:bg-slate-800 dark:text-white"
|
||||||
|
align="end"
|
||||||
|
>
|
||||||
<DropdownMenuGroup>
|
<DropdownMenuGroup>
|
||||||
<DropdownMenuItem
|
<DropdownMenuItem
|
||||||
v-for="item in linkItems"
|
v-for="item in linkItems"
|
||||||
:key="item.label"
|
:key="item.label"
|
||||||
v-slot="{ active }"
|
class="hover:bg-gray-100 dark:hover:bg-slate-700"
|
||||||
class="hover:bg-gray-100"
|
|
||||||
@click="item.onClick"
|
@click="item.onClick"
|
||||||
|
@mouseenter="activeKey = item.label"
|
||||||
|
@mouseleave="activeKey = null"
|
||||||
>
|
>
|
||||||
<Icon :name="item.icon" />
|
<Icon :name="item.icon ?? ''" />
|
||||||
<span :class="active ? 'text-sidebar-accent-foreground' : ''">{{ item.label }}</span>
|
<span :class="activeKey === item.label ? 'text-sidebar-accent-foreground' : ''">{{ item.label }}</span>
|
||||||
</DropdownMenuItem>
|
</DropdownMenuItem>
|
||||||
</DropdownMenuGroup>
|
</DropdownMenuGroup>
|
||||||
</DropdownMenuContent>
|
</DropdownMenuContent>
|
||||||
|
|||||||
@@ -60,11 +60,11 @@ const settingClass = computed(() => {
|
|||||||
'[&_.label]:md:w-44 [&_.label]:xl:w-52',
|
'[&_.label]:md:w-44 [&_.label]:xl:w-52',
|
||||||
][getLabelSizeIdx(props.labelSize)]
|
][getLabelSizeIdx(props.labelSize)]
|
||||||
} else {
|
} else {
|
||||||
cls += ' [&_.label]:pb-1 ';
|
cls += ' [&_.label]:pb-1 [&_.label]:!pt-0 ';
|
||||||
}
|
}
|
||||||
cls += ' [&:not(.preview)_.height-default]:pt-2 [&:not(.preview)_.height-default]:2xl:!pt-1.5 [&:not(.preview)_.height-compact]:!pt-1 '
|
cls += ' [&:not(.preview)_.height-default]:pt-2 [&:not(.preview)_.height-default]:2xl:!pt-1.5 [&:not(.preview)_.height-compact]:!pt-1 '
|
||||||
cls += '[&_textarea]:text-xs [&_textarea]:xl:text-sm '
|
cls += '[&_textarea]:text-xs [&_textarea]:2xl:!text-sm '
|
||||||
cls += '[&_label]:text-xs [&_label]:xl:text-sm'
|
cls += '[&_label]:text-xs [&_label]:2xl:!text-sm'
|
||||||
return cls
|
return cls
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -9,6 +9,6 @@ const props = defineProps({
|
|||||||
<template>
|
<template>
|
||||||
<div :class="`field ${props.defaultClass} ${props.class}`">
|
<div :class="`field ${props.defaultClass} ${props.class}`">
|
||||||
<slot />
|
<slot />
|
||||||
<div v-if="props.errMessage" class="mt-1 text-xs font-medium text-red-500">{{ props.errMessage }}</div>
|
<div v-if="props.errMessage" class="mt-1 md:text-xs 2xl:text-sm font-medium text-red-500">{{ props.errMessage }}</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ const settingClass = computed(() => {
|
|||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div :class="settingClass">
|
<div :class="settingClass">
|
||||||
<label>
|
<label v-bind="$attrs">
|
||||||
<slot />
|
<slot />
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -20,7 +20,12 @@ const forwarded = useForwardPropsEmits(delegatedProps, emits)
|
|||||||
<template>
|
<template>
|
||||||
<ComboboxItem
|
<ComboboxItem
|
||||||
v-bind="forwarded"
|
v-bind="forwarded"
|
||||||
:class="cn('relative flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm font-normal outline-none hover:bg-accent data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&>*]:text-sm [&>*]:font-normal', props.class)"
|
:class="
|
||||||
|
cn(
|
||||||
|
'relative flex cursor-default select-none items-center rounded-sm bg-white px-2 py-1.5 text-sm font-normal text-black outline-none hover:bg-accent data-[disabled]:pointer-events-none data-[disabled]:opacity-50 dark:bg-slate-800 dark:text-white dark:hover:bg-slate-700 [&>*]:text-sm [&>*]:font-normal',
|
||||||
|
props.class,
|
||||||
|
)
|
||||||
|
"
|
||||||
>
|
>
|
||||||
<slot />
|
<slot />
|
||||||
</ComboboxItem>
|
</ComboboxItem>
|
||||||
|
|||||||
@@ -20,11 +20,11 @@ function handleSelect(value: string) {
|
|||||||
<div class="leaf-node min-w-max">
|
<div class="leaf-node min-w-max">
|
||||||
<CommandItem
|
<CommandItem
|
||||||
:value="item.value"
|
:value="item.value"
|
||||||
class="flex items-center justify-between p-2 w-full text-sm font-normal hover:text-primary cursor-pointer rounded-md"
|
class="flex items-center justify-between p-2 w-full text-sm font-normal hover:text-primary cursor-pointer rounded-md bg-white dark:bg-transparent"
|
||||||
:class="{ 'pl-8': shouldAlign }"
|
:class="{ 'pl-8': shouldAlign }"
|
||||||
@select="() => handleSelect(item.value)"
|
@select="() => handleSelect(item.value)"
|
||||||
>
|
>
|
||||||
<span class="text-sm font-normal text-gray-400">{{ item.label }}</span>
|
<span class="text-sm font-normal text-gray-400 dark:text-gray-300">{{ item.label }}</span>
|
||||||
<Check
|
<Check
|
||||||
v-if="selectedValue === item.value"
|
v-if="selectedValue === item.value"
|
||||||
class="w-4 h-4 text-primary ml-2 flex-shrink-0"
|
class="w-4 h-4 text-primary ml-2 flex-shrink-0"
|
||||||
|
|||||||
@@ -52,19 +52,27 @@ watch(isOpen, async (newValue) => {
|
|||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="tree-node min-w-max">
|
<div class="tree-node min-w-max">
|
||||||
<Collapsible v-model:open="isOpen" class="w-full">
|
<Collapsible
|
||||||
|
v-model:open="isOpen"
|
||||||
|
class="w-full"
|
||||||
|
>
|
||||||
<!-- Node Header -->
|
<!-- Node Header -->
|
||||||
<div class="flex items-center justify-start w-full p-2 rounded-md hover:bg-accent gap-2">
|
<div
|
||||||
|
class="flex w-full items-center justify-start gap-2 rounded-md bg-white p-2 hover:bg-accent dark:bg-transparent dark:hover:bg-slate-700"
|
||||||
|
>
|
||||||
<!-- Chevron Toggle Button -->
|
<!-- Chevron Toggle Button -->
|
||||||
<CollapsibleTrigger as-child>
|
<CollapsibleTrigger as-child>
|
||||||
<Button
|
<Button
|
||||||
variant="ghost"
|
variant="ghost"
|
||||||
class="h-4 w-4 p-0 flex items-center justify-center"
|
class="flex h-4 w-4 items-center justify-center p-0"
|
||||||
>
|
>
|
||||||
<Loader2 v-if="isLoading" class="w-4 h-4 animate-spin text-muted-foreground" />
|
<Loader2
|
||||||
|
v-if="isLoading"
|
||||||
|
class="h-4 w-4 animate-spin text-muted-foreground"
|
||||||
|
/>
|
||||||
<ChevronRight
|
<ChevronRight
|
||||||
v-else
|
v-else
|
||||||
class="w-4 h-4 transition-transform duration-200 ease-in-out text-muted-foreground"
|
class="h-4 w-4 text-muted-foreground transition-transform duration-200 ease-in-out"
|
||||||
:class="{
|
:class="{
|
||||||
'rotate-90': isChevronRotated,
|
'rotate-90': isChevronRotated,
|
||||||
}"
|
}"
|
||||||
@@ -74,21 +82,24 @@ watch(isOpen, async (newValue) => {
|
|||||||
|
|
||||||
<!-- Node Label -->
|
<!-- Node Label -->
|
||||||
<span
|
<span
|
||||||
class="text-sm font-normal cursor-pointer hover:text-primary flex-1 flex items-center justify-between"
|
class="flex flex-1 cursor-pointer items-center justify-between text-sm font-normal text-black hover:text-primary dark:text-white"
|
||||||
@click="handleLabelClick"
|
@click="handleLabelClick"
|
||||||
>
|
>
|
||||||
{{ item.label }}
|
{{ item.label }}
|
||||||
<!-- Check Icon untuk selected state -->
|
<!-- Check Icon untuk selected state -->
|
||||||
<Check
|
<Check
|
||||||
v-if="selectedValue === item.value"
|
v-if="selectedValue === item.value"
|
||||||
class="w-4 h-4 text-primary ml-2 flex-shrink-0"
|
class="ml-2 h-4 w-4 flex-shrink-0 text-primary"
|
||||||
/>
|
/>
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Children Container -->
|
<!-- Children Container -->
|
||||||
<CollapsibleContent class="pl-6">
|
<CollapsibleContent class="pl-6">
|
||||||
<div v-if="!hasChildren" class="text-sm text-muted-foreground p-2">
|
<div
|
||||||
|
v-if="!hasChildren"
|
||||||
|
class="p-2 text-sm text-muted-foreground"
|
||||||
|
>
|
||||||
{{ isLoading ? 'Memuat...' : 'Tidak ada data' }}
|
{{ isLoading ? 'Memuat...' : 'Tidak ada data' }}
|
||||||
</div>
|
</div>
|
||||||
<TreeView
|
<TreeView
|
||||||
@@ -106,7 +117,7 @@ watch(isOpen, async (newValue) => {
|
|||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
.tree-node {
|
.tree-node {
|
||||||
@apply w-full;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Animasi tambahan untuk smooth transition */
|
/* Animasi tambahan untuk smooth transition */
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ const filteredData = computed(() => {
|
|||||||
// recursive filter
|
// recursive filter
|
||||||
function filterTree(items: TreeItem[]): TreeItem[] {
|
function filterTree(items: TreeItem[]): TreeItem[] {
|
||||||
return items
|
return items
|
||||||
.map(item => {
|
.map((item) => {
|
||||||
const match = item.label.toLowerCase().includes(searchValue.value.toLowerCase())
|
const match = item.label.toLowerCase().includes(searchValue.value.toLowerCase())
|
||||||
let children: TreeItem[] | undefined = undefined
|
let children: TreeItem[] | undefined = undefined
|
||||||
if (item.children) {
|
if (item.children) {
|
||||||
@@ -57,22 +57,28 @@ const filteredData = computed(() => {
|
|||||||
<template>
|
<template>
|
||||||
<Popover v-model:open="open">
|
<Popover v-model:open="open">
|
||||||
<PopoverTrigger as-child>
|
<PopoverTrigger as-child>
|
||||||
<Button variant="outline" role="combobox" class="w-full justify-between bg-white border-1 border-gray-400">
|
<Button
|
||||||
|
variant="outline"
|
||||||
|
role="combobox"
|
||||||
|
class="w-full justify-between border border-slate-200 bg-white text-black dark:border-slate-700 dark:bg-slate-800 dark:text-white"
|
||||||
|
>
|
||||||
<span
|
<span
|
||||||
class="font-normal text-muted-foreground" :class="cn(
|
class="font-normal text-muted-foreground"
|
||||||
'font-normal',
|
:class="cn('font-normal', !modelValue && 'text-muted-foreground', modelValue && 'text-black')"
|
||||||
!modelValue && 'text-muted-foreground',
|
|
||||||
modelValue && 'text-black',
|
|
||||||
)"
|
|
||||||
>
|
>
|
||||||
{{ selectedLabel }}
|
{{ selectedLabel }}
|
||||||
</span>
|
</span>
|
||||||
<ChevronsUpDown class="w-4 h-4 ml-2 opacity-50 shrink-0" />
|
<ChevronsUpDown class="ml-2 h-4 w-4 shrink-0 opacity-50" />
|
||||||
</Button>
|
</Button>
|
||||||
</PopoverTrigger>
|
</PopoverTrigger>
|
||||||
<PopoverContent class="min-w-full max-w-[350px] p-0">
|
<PopoverContent
|
||||||
|
class="min-w-full max-w-[350px] border border-slate-200 bg-white p-0 text-black dark:border-slate-700 dark:bg-slate-800 dark:text-white"
|
||||||
|
>
|
||||||
<Command>
|
<Command>
|
||||||
<CommandInput placeholder="Cari item..." v-model="searchValue" />
|
<CommandInput
|
||||||
|
placeholder="Cari item..."
|
||||||
|
v-model="searchValue"
|
||||||
|
/>
|
||||||
<CommandEmpty>Item tidak ditemukan.</CommandEmpty>
|
<CommandEmpty>Item tidak ditemukan.</CommandEmpty>
|
||||||
<CommandList class="max-h-[300px] overflow-x-auto overflow-y-auto">
|
<CommandList class="max-h-[300px] overflow-x-auto overflow-y-auto">
|
||||||
<CommandGroup>
|
<CommandGroup>
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import { cva } from 'class-variance-authority'
|
|||||||
export { default as Button } from './Button.vue'
|
export { default as Button } from './Button.vue'
|
||||||
|
|
||||||
export const buttonVariants = cva(
|
export const buttonVariants = cva(
|
||||||
'inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md md:tex-xs xl:text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0',
|
'inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md md:text-xs 2xl:text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0',
|
||||||
{
|
{
|
||||||
variants: {
|
variants: {
|
||||||
variant: {
|
variant: {
|
||||||
@@ -19,7 +19,7 @@ export const buttonVariants = cva(
|
|||||||
link: 'text-primary underline-offset-4 hover:underline',
|
link: 'text-primary underline-offset-4 hover:underline',
|
||||||
},
|
},
|
||||||
size: {
|
size: {
|
||||||
default: 'md:h8 xl:h-9 px-4 py-2',
|
default: 'md:h8 2xl:h-9 px-4 py-2',
|
||||||
xs: 'h-7 rounded px-2',
|
xs: 'h-7 rounded px-2',
|
||||||
sm: 'h-8 rounded-md px-3 text-xs',
|
sm: 'h-8 rounded-md px-3 text-xs',
|
||||||
lg: 'h-10 rounded-md px-8',
|
lg: 'h-10 rounded-md px-8',
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ const props = defineProps<{
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div :class="cn('p-4 xl:p-5 2xl:p-6', props.class)">
|
<div :class="cn('p-4 2xl:p-5', props.class)">
|
||||||
<slot />
|
<slot />
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ const props = defineProps<{
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<p :class="cn('text-sm text-muted-foreground', props.class)">
|
<p :class="cn('text-xs 2xl:text-sm text-muted-foreground', props.class)">
|
||||||
<slot />
|
<slot />
|
||||||
</p>
|
</p>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ const props = defineProps<{
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div :class="cn('flex items-center p-6 pt-0', props.class)">
|
<div :class="cn('flex items-center p-4 2xl:p-5 pt-0', props.class)">
|
||||||
<slot />
|
<slot />
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ const forwarded = useForwardPropsEmits(delegatedProps, emits)
|
|||||||
<CheckboxRoot
|
<CheckboxRoot
|
||||||
v-bind="forwarded"
|
v-bind="forwarded"
|
||||||
:class="
|
:class="
|
||||||
cn('peer h-4 w-4 shrink-0 rounded-sm border border-primary shadow focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50 data-[state=checked]:bg-primary data-[state=checked]:text-primary-foreground',
|
cn('peer h-6 w-6 md:h-5 md:w-5 2xl:h-6 2xl:w-6 shrink-0 rounded-sm border border-primary shadow focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50 data-[state=checked]:bg-primary data-[state=checked]:text-primary-foreground',
|
||||||
props.class)"
|
props.class)"
|
||||||
>
|
>
|
||||||
<CheckboxIndicator class="h-full w-full flex items-center justify-center text-current">
|
<CheckboxIndicator class="h-full w-full flex items-center justify-center text-current">
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ const { formDescriptionId } = useFormField()
|
|||||||
<template>
|
<template>
|
||||||
<p
|
<p
|
||||||
:id="formDescriptionId"
|
:id="formDescriptionId"
|
||||||
:class="cn('text-sm text-muted-foreground', props.class)"
|
:class="cn('md:text-xs 2xl:text-sm text-muted-foreground', props.class)"
|
||||||
>
|
>
|
||||||
<slot />
|
<slot />
|
||||||
</p>
|
</p>
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ const modelValue = useVModel(props, 'modelValue', emits, {
|
|||||||
v-model="modelValue"
|
v-model="modelValue"
|
||||||
:class="
|
:class="
|
||||||
cn(
|
cn(
|
||||||
'border-input dark:bg-slate-950 ring-offset-background placeholder:text-muted-foreground flex h-8 xl:h-9 w-full rounded-md border border-gray-400 px-3 py-2 md:text-xs xl:text-sm file:border-0 file:bg-transparent md:file:text-xs xl:file:text-sm file:font-medium disabled:cursor-not-allowed disabled:opacity-50',
|
'border-input dark:bg-slate-950 ring-offset-background placeholder:text-muted-foreground flex h-8 2xl:h-9 w-full rounded-md border border-gray-400 px-3 py-2 md:text-xs 2xl:text-sm file:border-0 file:bg-transparent md:file:text-xs xl:file:text-sm file:font-medium disabled:cursor-not-allowed disabled:opacity-50',
|
||||||
props.class,
|
props.class,
|
||||||
)
|
)
|
||||||
"
|
"
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ const delegatedProps = computed(() => {
|
|||||||
v-bind="delegatedProps"
|
v-bind="delegatedProps"
|
||||||
:class="
|
:class="
|
||||||
cn(
|
cn(
|
||||||
'md:!text-xs xl:text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70',
|
'md:!text-xs 2xl:text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70',
|
||||||
props.class,
|
props.class,
|
||||||
)
|
)
|
||||||
"
|
"
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ const { isMobile, state, openMobile, setOpenMobile } = useSidebar()
|
|||||||
<template>
|
<template>
|
||||||
<div
|
<div
|
||||||
v-if="collapsible === 'none'"
|
v-if="collapsible === 'none'"
|
||||||
:class="cn('bg-sidebar text-sidebar-foreground flex h-full w-[--sidebar-width] flex-col', props.class)"
|
:class="cn('bg-sidebar text-sidebar-foreground flex h-full w-[--sidebar-width] 2xl:w-[--xxl-sidebar-width] flex-col', props.class)"
|
||||||
v-bind="$attrs"
|
v-bind="$attrs"
|
||||||
>
|
>
|
||||||
<slot />
|
<slot />
|
||||||
@@ -64,7 +64,7 @@ const { isMobile, state, openMobile, setOpenMobile } = useSidebar()
|
|||||||
<div
|
<div
|
||||||
:class="
|
:class="
|
||||||
cn(
|
cn(
|
||||||
'relative h-svh w-[--sidebar-width] bg-transparent transition-[width] duration-200 ease-linear',
|
'relative h-svh w-[--sidebar-width] 2xl:w-[--xxl-sidebar-width] bg-transparent transition-[width] duration-200 ease-linear',
|
||||||
'group-data-[collapsible=offcanvas]:w-0',
|
'group-data-[collapsible=offcanvas]:w-0',
|
||||||
'group-data-[side=right]:rotate-180',
|
'group-data-[side=right]:rotate-180',
|
||||||
variant === 'floating' || variant === 'inset'
|
variant === 'floating' || variant === 'inset'
|
||||||
@@ -76,10 +76,10 @@ const { isMobile, state, openMobile, setOpenMobile } = useSidebar()
|
|||||||
<div
|
<div
|
||||||
:class="
|
:class="
|
||||||
cn(
|
cn(
|
||||||
'fixed inset-y-0 z-10 hidden h-svh w-[--sidebar-width] transition-[left,right,width] duration-200 ease-linear md:flex',
|
'fixed inset-y-0 z-10 hidden h-svh w-[--sidebar-width] 2xl:w-[--xxl-sidebar-width] transition-[left,right,width] duration-200 ease-linear md:flex',
|
||||||
side === 'left'
|
side === 'left'
|
||||||
? 'left-0 group-data-[collapsible=offcanvas]:left-[calc(var(--sidebar-width)*-1)]'
|
? 'left-0 group-data-[collapsible=offcanvas]:left-[calc(var(--sidebar-width)*-1)] group-data-[collapsible=offcanvas]:2xl:left-[calc(var(--xxl-sidebar-width)*-1)]'
|
||||||
: 'right-0 group-data-[collapsible=offcanvas]:right-[calc(var(--sidebar-width)*-1)]',
|
: 'right-0 group-data-[collapsible=offcanvas]:right-[calc(var(--sidebar-width)*-1)] group-data-[collapsible=offcanvas]:2xl:right-[calc(var(--xxl-sidebar-width)*-1)]',
|
||||||
// Adjust the padding for floating and inset variants.
|
// Adjust the padding for floating and inset variants.
|
||||||
variant === 'floating' || variant === 'inset'
|
variant === 'floating' || variant === 'inset'
|
||||||
? 'p-2 group-data-[collapsible=icon]:w-[calc(var(--sidebar-width-icon)_+_1rem_+_2px)]'
|
? 'p-2 group-data-[collapsible=icon]:w-[calc(var(--sidebar-width-icon)_+_1rem_+_2px)]'
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user