fix: resolve conflict
This commit is contained in:
@@ -0,0 +1,73 @@
|
||||
<script setup lang="ts">
|
||||
// Pubs
|
||||
import * as DE from '~/components/pub/my-ui/doc-entry'
|
||||
import * as CB from '~/components/pub/my-ui/combobox'
|
||||
import Nav from '~/components/pub/my-ui/nav-footer/cl-sa.vue'
|
||||
|
||||
// This scope
|
||||
import type { DeviceOrderItem } from '~/models/device-order-item';
|
||||
import type { Device } from '~/models/device';
|
||||
|
||||
// Props
|
||||
const props = defineProps<{
|
||||
data: DeviceOrderItem
|
||||
devices: Device[]
|
||||
}>()
|
||||
|
||||
// Refs
|
||||
const { devices } = toRefs(props)
|
||||
const deviceItems = ref<CB.Item[]>([])
|
||||
|
||||
// Nav actions
|
||||
type ClickType = 'close' | 'save'
|
||||
|
||||
// Emits
|
||||
const emit = defineEmits<{
|
||||
close: [],
|
||||
save: [data: DeviceOrderItem],
|
||||
'update:searchText': [value: string]
|
||||
}>()
|
||||
|
||||
// Reactivities
|
||||
watch(devices, (data) => {
|
||||
deviceItems.value = CB.objectsToItems(data, 'code', 'name')
|
||||
})
|
||||
|
||||
// Functions
|
||||
function searchDeviceText(value: string) {
|
||||
emit('update:searchText', value)
|
||||
}
|
||||
|
||||
function navClick(type: ClickType) {
|
||||
if (type === 'close') {
|
||||
emit('close')
|
||||
} else if (type === 'save') {
|
||||
emit('save', props.data)
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<DE.Block :colCount="4" :cellFlex="false">
|
||||
<DE.Cell :colSpan="4">
|
||||
<DE.Label>Nama</DE.Label>
|
||||
<DE.Field>
|
||||
<CB.Combobox
|
||||
v-model="data.device_code"
|
||||
:items="deviceItems"
|
||||
@update:searchText="searchDeviceText"
|
||||
/>
|
||||
</DE.Field>
|
||||
</DE.Cell>
|
||||
<DE.Cell>
|
||||
<DE.Label>Jumlah</DE.Label>
|
||||
<DE.Field>
|
||||
<Input v-model="data.quantity" type="number" />
|
||||
</DE.Field>
|
||||
</DE.Cell>
|
||||
</DE.Block>
|
||||
<Separator class="my-5" />
|
||||
<div class="flex justify-center">
|
||||
<Nav @click="navClick" />
|
||||
</div>
|
||||
</template>
|
||||
@@ -1,36 +1,35 @@
|
||||
import { defineAsyncComponent } from 'vue'
|
||||
import type { Config } from '~/components/pub/my-ui/data-table'
|
||||
|
||||
import type { Config, RecComponent } from '~/components/pub/my-ui/data-table'
|
||||
|
||||
const action = defineAsyncComponent(() => import('~/components/pub/my-ui/data/dropdown-action-ud.vue'))
|
||||
|
||||
export const config: Config = {
|
||||
cols: [{}, {}, { width: 50 }],
|
||||
cols: [{}, { width: 200 }, { width: 100 }],
|
||||
headers: [[{ label: 'Nama' }, { label: 'Jumlah' }, { label: '' }]],
|
||||
keys: ['name', 'count', 'action'],
|
||||
keys: ['device.name', 'quantity', 'action'],
|
||||
delKeyNames: [
|
||||
{ key: 'name', label: 'Nama' },
|
||||
{ key: 'count', label: 'Jumlah' },
|
||||
],
|
||||
skeletonSize: 10
|
||||
skeletonSize: 10,
|
||||
// funcParsed: {
|
||||
// parent: (rec: unknown): unknown => {
|
||||
// const recX = rec as SmallDetailDto
|
||||
// return recX.parent?.name || '-'
|
||||
// },
|
||||
// },
|
||||
// funcComponent: {
|
||||
// action(rec: object, idx: any) {
|
||||
// const res: RecComponent = {
|
||||
// idx,
|
||||
// rec: rec as object,
|
||||
// component: action,
|
||||
// props: {
|
||||
// size: 'sm',
|
||||
// },
|
||||
// }
|
||||
// return res
|
||||
// },
|
||||
// }
|
||||
components: {
|
||||
action(rec, idx) {
|
||||
const res: RecComponent = {
|
||||
idx,
|
||||
rec: rec as object,
|
||||
component: action,
|
||||
props: {
|
||||
size: 'sm',
|
||||
},
|
||||
}
|
||||
return res
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,13 +1,23 @@
|
||||
<script setup lang="ts">
|
||||
import DataTable from '~/components/pub/my-ui/data-table/data-table.vue'
|
||||
import { config } from './list-entry.config'
|
||||
import type { DeviceOrderItem } from '~/models/device-order-item';
|
||||
|
||||
defineProps<{
|
||||
data: DeviceOrderItem[]
|
||||
}>()
|
||||
|
||||
const emit = defineEmits<{
|
||||
add: []
|
||||
}>()
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<DataTable v-bind="config" :rows="[]" class="border mb-3 2xl:mb-4" />
|
||||
<DataTable v-bind="config" :rows="data" class="border mb-3 2xl:mb-4" />
|
||||
<div>
|
||||
<Button>
|
||||
Tambah
|
||||
<Button @click="emit('add')">
|
||||
<Icon name="i-lucide-plus" />
|
||||
Tambah Item
|
||||
</Button>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
<script setup lang="ts">
|
||||
import type { DeviceOrder } from '~/models/device-order'
|
||||
import * as DE from '~/components/pub/my-ui/doc-entry'
|
||||
|
||||
defineProps<{
|
||||
data: DeviceOrder | null | undefined
|
||||
}>()
|
||||
</script>
|
||||
<template>
|
||||
<DE.Block mode="preview" label-size="small" class="!mb-0">
|
||||
<DE.Cell>
|
||||
<DE.Label>Tgl. Order</DE.Label>
|
||||
<DE.Colon />
|
||||
<DE.Field>
|
||||
{{ data?.createdAt?.substring(0, 10) }}
|
||||
</DE.Field>
|
||||
</DE.Cell>
|
||||
<DE.Cell>
|
||||
<DE.Label>DPJP</DE.Label>
|
||||
<DE.Colon />
|
||||
<DE.Field>
|
||||
{{ data?.doctor?.employee?.person?.name }}
|
||||
</DE.Field>
|
||||
</DE.Cell>
|
||||
</DE.Block>
|
||||
</template>
|
||||
@@ -1,6 +1,25 @@
|
||||
<script setup lang="ts">
|
||||
import * as DE from '~/components/pub/my-ui/doc-entry'
|
||||
import type { DeviceOrder } from '~/models/device-order';
|
||||
|
||||
defineProps<{
|
||||
data: DeviceOrder
|
||||
}>()
|
||||
</script>
|
||||
|
||||
<template>
|
||||
Test
|
||||
<DE.Block :col-count="2" mode="preview">
|
||||
<DE.Cell>
|
||||
<DE.Label>Tanggal</DE.Label>
|
||||
<DE.Field>
|
||||
{{ data?.createdAt?.substring(0, 10) }}
|
||||
</DE.Field>
|
||||
</DE.Cell>
|
||||
<DE.Cell>
|
||||
<DE.Label>DPJP</DE.Label>
|
||||
<DE.Field>
|
||||
{{ data?.doctor?.employee?.person?.name }}
|
||||
</DE.Field>
|
||||
</DE.Cell>
|
||||
</DE.Block>
|
||||
</template>
|
||||
|
||||
@@ -1,13 +1,18 @@
|
||||
import type { Config } from '~/components/pub/my-ui/data-table'
|
||||
import type { Config, RecComponent } from '~/components/pub/my-ui/data-table'
|
||||
import type { DeviceOrder } from '~/models/device-order'
|
||||
import { defineAsyncComponent } from 'vue'
|
||||
import type { DeviceOrderItem } from '~/models/device-order-item'
|
||||
|
||||
const action = defineAsyncComponent(() => import('~/components/pub/my-ui/data/dropdown-action-ud.vue'))
|
||||
const action = defineAsyncComponent(() => import('~/components/pub/my-ui/data/dropdown-action-dsd.vue'))
|
||||
|
||||
export const config: Config = {
|
||||
cols: [{ width: 120 }, { }, { }, { width: 50 }],
|
||||
headers: [[{ label: 'Tanggal' }, { label: 'DPJP' }, { label: 'Alat Kesehatan' }, { label: '' }]],
|
||||
keys: ['createdAt', 'encounter.doctor.person.name', 'items', 'action'],
|
||||
cols: [{ width: 120 }, { }, { }, { }, { width: 50 }],
|
||||
headers: [[
|
||||
{ label: 'Tanggal' },
|
||||
{ label: 'DPJP' },
|
||||
{ label: 'Alat Kesehatan' },
|
||||
{ label: 'Status' },
|
||||
{ label: '' }]],
|
||||
keys: ['createdAt', 'doctor.employee.person.name', 'items', 'status_code', 'action'],
|
||||
delKeyNames: [
|
||||
{ key: 'code', label: 'Kode' },
|
||||
{ key: 'name', label: 'Nama' },
|
||||
@@ -16,27 +21,45 @@ export const config: Config = {
|
||||
htmls: {
|
||||
items: (rec: unknown): unknown => {
|
||||
const recX = rec as DeviceOrder
|
||||
return recX.items?.length || 0
|
||||
if (recX.items?.length > 0) {
|
||||
let output = '<table><tbody>'
|
||||
recX.items.forEach((item: DeviceOrderItem) => {
|
||||
output += '' +
|
||||
'<tr>'+
|
||||
`<td class="pe-10">${item.device?.name}</td>` +
|
||||
'<td class="w-4">:</td>' +
|
||||
`<td class="w-10">${item.quantity}</td>` +
|
||||
'</tr>'
|
||||
})
|
||||
output += '</tbody></table>'
|
||||
return output
|
||||
} else {
|
||||
return '-'
|
||||
}
|
||||
},
|
||||
},
|
||||
parses: {
|
||||
createdAt: (rec: unknown): unknown => {
|
||||
const recX = rec as DeviceOrder
|
||||
return recX.createdAt ? new Date(recX.createdAt).toLocaleDateString() : '-'
|
||||
},
|
||||
// parent: (rec: unknown): unknown => {
|
||||
// const recX = rec as SmallDetailDto
|
||||
// return recX.parent?.name || '-'
|
||||
// },
|
||||
},
|
||||
components: {
|
||||
action(rec, idx) {
|
||||
const res: RecComponent = {
|
||||
idx,
|
||||
rec: rec as object,
|
||||
component: action,
|
||||
props: {
|
||||
size: 'sm',
|
||||
},
|
||||
}
|
||||
return res
|
||||
},
|
||||
}
|
||||
// funcParsed: {
|
||||
// parent: (rec: unknown): unknown => {
|
||||
// const recX = rec as SmallDetailDto
|
||||
// return recX.parent?.name || '-'
|
||||
// },
|
||||
// },
|
||||
// funcComponent: {
|
||||
// action(rec: object, idx: any) {
|
||||
// const res: RecComponent = {
|
||||
// idx,
|
||||
// rec: rec as object,
|
||||
// component: action,
|
||||
// props: {
|
||||
// size: 'sm',
|
||||
// },
|
||||
// }
|
||||
// return res
|
||||
// },
|
||||
// }
|
||||
}
|
||||
|
||||
|
||||
@@ -8,12 +8,10 @@ import type { PaginationMeta } from '~/components/pub/my-ui/pagination/paginatio
|
||||
// Configs
|
||||
import { config } from './list.config'
|
||||
|
||||
interface Props {
|
||||
defineProps<{
|
||||
data: any[]
|
||||
paginationMeta: PaginationMeta
|
||||
}
|
||||
|
||||
defineProps<Props>()
|
||||
}>()
|
||||
|
||||
const emit = defineEmits<{
|
||||
pageChange: [page: number]
|
||||
@@ -28,7 +26,7 @@ function handlePageChange(page: number) {
|
||||
<div class="space-y-4">
|
||||
<PubMyUiDataTable
|
||||
v-bind="config"
|
||||
:rows="[]"
|
||||
:rows="data"
|
||||
/>
|
||||
<PaginationView :pagination-meta="paginationMeta" @page-change="handlePageChange" />
|
||||
</div>
|
||||
|
||||
@@ -0,0 +1,71 @@
|
||||
<script setup lang="ts">
|
||||
import type { FormErrors } from '~/types/error'
|
||||
import Combobox from '~/components/pub/my-ui/combobox/combobox.vue'
|
||||
import { cn, mapToComboboxOptList } from '~/lib/utils'
|
||||
import { docTypeCode, supportingDocOpt, type docTypeCodeKey } from '~/lib/constants'
|
||||
import { getValueLabelList as getDoctorLabelList } from '~/services/doctor.service'
|
||||
import { getValueLabelList as getUnitLabelList } from '~/services/unit.service'
|
||||
|
||||
import * as DE from '~/components/pub/my-ui/doc-entry'
|
||||
import type { Item } from '~/components/pub/my-ui/combobox'
|
||||
|
||||
const props = defineProps<{
|
||||
fieldName?: string
|
||||
label?: string
|
||||
placeholder?: string
|
||||
errors?: FormErrors
|
||||
class?: string
|
||||
selectClass?: string
|
||||
fieldGroupClass?: string
|
||||
labelClass?: string
|
||||
isRequired?: boolean
|
||||
}>()
|
||||
|
||||
const {
|
||||
fieldName = 'job',
|
||||
label = 'Pekerjaan',
|
||||
placeholder = 'Pilih pekerjaan',
|
||||
errors,
|
||||
class: containerClass,
|
||||
fieldGroupClass,
|
||||
labelClass,
|
||||
} = props
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<DE.Cell :class="cn('select-field-group', fieldGroupClass, containerClass)">
|
||||
<DE.Label
|
||||
:label-for="fieldName"
|
||||
:class="cn('select-field-label', labelClass)"
|
||||
:is-required="isRequired"
|
||||
>
|
||||
{{ label }}
|
||||
</DE.Label>
|
||||
<DE.Field
|
||||
:id="fieldName"
|
||||
:errors="errors"
|
||||
:class="cn('select-field-wrapper')"
|
||||
>
|
||||
<FormField
|
||||
v-slot="{ componentField }"
|
||||
:name="fieldName"
|
||||
>
|
||||
<FormItem>
|
||||
<FormControl>
|
||||
<Combobox
|
||||
class="focus:ring-0 focus:ring-offset-0"
|
||||
:id="fieldName"
|
||||
v-bind="componentField"
|
||||
:items="supportingDocOpt"
|
||||
:placeholder="placeholder"
|
||||
search-placeholder="Cari..."
|
||||
empty-message="Data tidak ditemukan"
|
||||
/>
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
</FormField>
|
||||
</DE.Field>
|
||||
</DE.Cell>
|
||||
</template>
|
||||
@@ -0,0 +1,73 @@
|
||||
<script setup lang="ts">
|
||||
import type { FormErrors } from '~/types/error'
|
||||
import { toTypedSchema } from '@vee-validate/zod'
|
||||
import { Form } from '~/components/pub/ui/form'
|
||||
import InputBase from '~/components/pub/my-ui/form/input-base.vue'
|
||||
import * as DE from '~/components/pub/my-ui/doc-entry'
|
||||
import FileField from '~/components/pub/my-ui/form/file-field.vue'
|
||||
import SelectDocType from './_common/select-doc-type.vue'
|
||||
import Separator from '~/components/pub/ui/separator/Separator.vue'
|
||||
|
||||
const props = defineProps<{
|
||||
schema: any
|
||||
initialValues?: any
|
||||
errors?: FormErrors
|
||||
}>()
|
||||
|
||||
const formSchema = toTypedSchema(props.schema)
|
||||
const formRef = ref()
|
||||
|
||||
defineExpose({
|
||||
validate: () => formRef.value?.validate(),
|
||||
resetForm: () => formRef.value?.resetForm(),
|
||||
setValues: (values: any, shouldValidate = true) => formRef.value?.setValues(values, shouldValidate),
|
||||
values: computed(() => formRef.value?.values),
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Form
|
||||
ref="formRef"
|
||||
v-slot="{ values }"
|
||||
as=""
|
||||
keep-values
|
||||
:validation-schema="formSchema"
|
||||
:validate-on-mount="false"
|
||||
validation-mode="onSubmit"
|
||||
:initial-values="initialValues ? initialValues : {}"
|
||||
>
|
||||
<DE.Block :col-count="2" :cell-flex="false">
|
||||
<InputBase
|
||||
field-name="officer"
|
||||
label="Petugas Upload"
|
||||
placeholder="Masukkan Petugas Upload"
|
||||
:is-disabled="true"
|
||||
/>
|
||||
<DE.Cell :col-span="2">
|
||||
<Separator class="w-full my-4"/>
|
||||
<DE.Block :col-count="3" :cell-flex="false">
|
||||
<InputBase
|
||||
field-name="name"
|
||||
label="Nama Dokumen"
|
||||
placeholder="Maukkan Nama Dokumen"
|
||||
/>
|
||||
<SelectDocType
|
||||
field-name="type_code"
|
||||
label="Tipe Dokumen"
|
||||
placeholder="Pilih Jenis Dokumen"
|
||||
:errors="errors"
|
||||
is-required
|
||||
/>
|
||||
<FileField
|
||||
field-name="content"
|
||||
label="Upload Dokumen"
|
||||
placeholder="Unggah dokumen"
|
||||
:errors="errors"
|
||||
:accept="['pdf', 'jpg', 'png']"
|
||||
:max-size-mb="1"
|
||||
/>
|
||||
</DE.Block>
|
||||
</DE.Cell>
|
||||
</DE.Block>
|
||||
</Form>
|
||||
</template>
|
||||
@@ -0,0 +1,43 @@
|
||||
import type { Config } from '~/components/pub/my-ui/data-table'
|
||||
import { defineAsyncComponent } from 'vue'
|
||||
import { docTypeCode, docTypeLabel, type docTypeCodeKey } from '~/lib/constants'
|
||||
|
||||
const action = defineAsyncComponent(() => import('~/components/pub/my-ui/data/dropdown-action-dd.vue'))
|
||||
|
||||
export const config: Config = {
|
||||
cols: [{}, {}, {}, {width: 50},],
|
||||
|
||||
headers: [
|
||||
[
|
||||
{ label: 'Nama Dokumen' },
|
||||
{ label: 'Tipe Dokumen' },
|
||||
{ label: 'Petugas Upload' },
|
||||
{ label: 'Action' },
|
||||
],
|
||||
],
|
||||
|
||||
keys: ['fileName', 'type_code', 'employee.name', 'action'],
|
||||
|
||||
delKeyNames: [
|
||||
|
||||
],
|
||||
|
||||
parses: {
|
||||
type_code: (v: unknown) => {
|
||||
return docTypeLabel[v?.type_code as docTypeCodeKey]
|
||||
},
|
||||
},
|
||||
|
||||
components: {
|
||||
action(rec, idx) {
|
||||
return {
|
||||
idx,
|
||||
rec: rec as object,
|
||||
component: action,
|
||||
}
|
||||
},
|
||||
},
|
||||
|
||||
htmls: {
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
<script setup lang="ts">
|
||||
import type { PaginationMeta } from '~/components/pub/my-ui/pagination/pagination.type'
|
||||
import PaginationView from '~/components/pub/my-ui/pagination/pagination-view.vue'
|
||||
import { config } from './list.cfg'
|
||||
|
||||
interface Props {
|
||||
data: any[]
|
||||
paginationMeta: PaginationMeta
|
||||
}
|
||||
|
||||
defineProps<Props>()
|
||||
|
||||
const emit = defineEmits<{
|
||||
pageChange: [page: number]
|
||||
}>()
|
||||
|
||||
function handlePageChange(page: number) {
|
||||
emit('pageChange', page)
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="space-y-4">
|
||||
<PubMyUiDataTable
|
||||
v-bind="config"
|
||||
:rows="data"
|
||||
:skeleton-size="paginationMeta?.pageSize"
|
||||
/>
|
||||
<PaginationView :pagination-meta="paginationMeta" @page-change="handlePageChange" />
|
||||
</div>
|
||||
</template>
|
||||
@@ -0,0 +1,214 @@
|
||||
<script setup lang="ts">
|
||||
import Block from '~/components/pub/my-ui/doc-entry/block.vue'
|
||||
import Cell from '~/components/pub/my-ui/doc-entry/cell.vue'
|
||||
import Field from '~/components/pub/my-ui/doc-entry/field.vue'
|
||||
import Label from '~/components/pub/my-ui/doc-entry/label.vue'
|
||||
// Helpers
|
||||
import type z from 'zod'
|
||||
import { toTypedSchema } from '@vee-validate/zod'
|
||||
import { useForm } from 'vee-validate'
|
||||
// import { ref, watch, inject } from 'vue'
|
||||
|
||||
const props = defineProps<{
|
||||
modelValue: any
|
||||
schema: z.ZodSchema<any>
|
||||
excludeFields?: string[]
|
||||
isReadonly?: boolean
|
||||
}>()
|
||||
|
||||
const emit = defineEmits<{
|
||||
(e: 'update:modelValue', val: any): void
|
||||
(e: 'submit', val: any): void
|
||||
}>()
|
||||
|
||||
// Setup form
|
||||
const {
|
||||
validate: _validate,
|
||||
defineField,
|
||||
handleSubmit,
|
||||
errors,
|
||||
values,
|
||||
} = useForm({
|
||||
validationSchema: toTypedSchema(props.schema),
|
||||
initialValues: props.modelValue,
|
||||
})
|
||||
|
||||
watch(values, (val) => emit('update:modelValue', val), { deep: true })
|
||||
|
||||
// Define form fields
|
||||
const [relatives, relativesAttrs] = defineField('relatives')
|
||||
const [responsibleName, responsibleNameAttrs] = defineField('responsibleName')
|
||||
const [responsiblePhone, responsiblePhoneAttrs] = defineField('responsiblePhone')
|
||||
const [informant, informantAttrs] = defineField('informant')
|
||||
const [witness1, witness1Attrs] = defineField('witness1')
|
||||
const [witness2, witness2Attrs] = defineField('witness2')
|
||||
const [tanggal, tanggalAttrs] = defineField('tanggal')
|
||||
|
||||
// Relatives list handling
|
||||
const addRelative = () => {
|
||||
relatives.value = [...(relatives.value || []), { name: '', phone: '' }]
|
||||
}
|
||||
|
||||
const removeRelative = (index: number) => {
|
||||
relatives.value = relatives.value.filter((_: any, i: number) => i !== index)
|
||||
}
|
||||
|
||||
const validate = async () => {
|
||||
const result = await _validate()
|
||||
return {
|
||||
valid: true,
|
||||
data: result.values,
|
||||
errors: result.errors,
|
||||
}
|
||||
}
|
||||
|
||||
defineExpose({ validate })
|
||||
|
||||
const icdPreview = inject('icdPreview')
|
||||
|
||||
const isExcluded = (key: string) => props.excludeFields?.includes(key)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<form id="entry-form">
|
||||
<div class="mb-5 border-b border-b-slate-300 pb-3 text-lg xl:text-xl">
|
||||
<Block>
|
||||
<Cell>
|
||||
<Label dynamic>Tanggal</Label>
|
||||
<Field>
|
||||
<Input
|
||||
v-model="tanggal"
|
||||
v-bind="tanggalAttrs"
|
||||
:disabled="props.isReadonly"
|
||||
/>
|
||||
</Field>
|
||||
</Cell>
|
||||
</Block>
|
||||
|
||||
<Separator class="mt-8" />
|
||||
|
||||
<div class="my-2 flex items-center justify-between">
|
||||
<h1 class="font-semibold">Anggota Keluarga</h1>
|
||||
<Button
|
||||
type="button"
|
||||
@click="addRelative"
|
||||
>
|
||||
+ Tambah
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
<div
|
||||
v-for="(item, idx) in relatives"
|
||||
:key="idx"
|
||||
class="my-2 rounded-md border border-slate-300 p-4"
|
||||
>
|
||||
<Block :colCount="2">
|
||||
<Cell>
|
||||
<Label dynamic>Nama Anggota Keluarga</Label>
|
||||
<Field>
|
||||
<Input v-model="relatives[idx].name" />
|
||||
</Field>
|
||||
</Cell>
|
||||
|
||||
<Cell>
|
||||
<Label dynamic>No. Hp Anggota Keluarga</Label>
|
||||
<Field>
|
||||
<Input v-model="relatives[idx].phone" />
|
||||
</Field>
|
||||
</Cell>
|
||||
</Block>
|
||||
|
||||
<button
|
||||
type="button"
|
||||
class="mt-3 text-sm text-red-500"
|
||||
@click="removeRelative(idx)"
|
||||
>
|
||||
Hapus
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<Separator class="mt-8" />
|
||||
|
||||
<!-- Responsible Section -->
|
||||
<div class="my-2">
|
||||
<h1 class="font-semibold">Penanggung Jawab</h1>
|
||||
</div>
|
||||
|
||||
<div class="my-2 rounded-md border border-slate-300 p-4">
|
||||
<Block :colCount="2">
|
||||
<Cell>
|
||||
<Label dynamic>Nama Penanggung Jawab</Label>
|
||||
<Field>
|
||||
<Input
|
||||
v-model="responsibleName"
|
||||
v-bind="responsibleNameAttrs"
|
||||
/>
|
||||
</Field>
|
||||
</Cell>
|
||||
|
||||
<Cell>
|
||||
<Label dynamic>No. Hp Penanggung Jawab</Label>
|
||||
<Field>
|
||||
<Input
|
||||
v-model="responsiblePhone"
|
||||
v-bind="responsiblePhoneAttrs"
|
||||
/>
|
||||
</Field>
|
||||
</Cell>
|
||||
</Block>
|
||||
</div>
|
||||
|
||||
<Separator class="mt-8" />
|
||||
|
||||
<!-- Informant -->
|
||||
<div class="my-2">
|
||||
<h1 class="font-semibold">Pemberi Informasi</h1>
|
||||
</div>
|
||||
|
||||
<div class="my-2 rounded-md border border-slate-300 p-4">
|
||||
<Block>
|
||||
<Cell>
|
||||
<Label dynamic>Informant</Label>
|
||||
<Field>
|
||||
<Input
|
||||
v-model="informant"
|
||||
v-bind="informantAttrs"
|
||||
/>
|
||||
</Field>
|
||||
</Cell>
|
||||
</Block>
|
||||
</div>
|
||||
|
||||
<Separator class="mt-8" />
|
||||
|
||||
<!-- Witnesses -->
|
||||
<div class="my-2">
|
||||
<h1 class="font-semibold">Saksi</h1>
|
||||
</div>
|
||||
|
||||
<div class="my-2 rounded-md border border-slate-300 p-4">
|
||||
<Block :colCount="2">
|
||||
<Cell>
|
||||
<Label dynamic>Saksi 1</Label>
|
||||
<Field>
|
||||
<Input
|
||||
v-model="witness1"
|
||||
v-bind="witness1Attrs"
|
||||
/>
|
||||
</Field>
|
||||
</Cell>
|
||||
|
||||
<Cell>
|
||||
<Label dynamic>Saksi 2</Label>
|
||||
<Field>
|
||||
<Input
|
||||
v-model="witness2"
|
||||
v-bind="witness2Attrs"
|
||||
/>
|
||||
</Field>
|
||||
</Cell>
|
||||
</Block>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</template>
|
||||
@@ -0,0 +1,82 @@
|
||||
import type { Config, RecComponent, RecStrFuncComponent, RecStrFuncUnknown } from '~/components/pub/my-ui/data-table'
|
||||
import { defineAsyncComponent } from 'vue'
|
||||
import type { GeneralConsent } from '~/models/general-consent'
|
||||
|
||||
type SmallDetailDto = any
|
||||
|
||||
const action = defineAsyncComponent(() => import('~/components/pub/my-ui/data/dropdown-action-ud.vue'))
|
||||
export const config: Config = {
|
||||
cols: [{ width: 100 }, {}, {}, {}, { width: 50 }],
|
||||
headers: [
|
||||
[
|
||||
{ label: 'Tanggal' },
|
||||
{ label: 'Anggota Keluarga' },
|
||||
{ label: 'Penanggung Jawab' },
|
||||
{ label: 'Pemberi Informasi' },
|
||||
{ label: 'Saksi 1' },
|
||||
{ label: 'Saksi 2' },
|
||||
{ label: '' },
|
||||
],
|
||||
],
|
||||
keys: ['date', 'relatives', 'responsible', 'informant', 'witness1', 'witness2', 'action'],
|
||||
delKeyNames: [
|
||||
{ key: 'data', label: 'Tanggal' },
|
||||
{ key: 'dstDoctor.name', label: 'Dokter' },
|
||||
],
|
||||
parses: {
|
||||
date(rec) {
|
||||
const recX = rec as GeneralConsent
|
||||
return recX?.createdAt?.substring(0, 10) || '-'
|
||||
},
|
||||
relatives(rec) {
|
||||
const recX = rec as GeneralConsent
|
||||
const parsed = JSON.parse(recX?.value || '{}')
|
||||
return parsed?.relatives?.join(', ') || '-'
|
||||
},
|
||||
responsible(rec) {
|
||||
const recX = rec as GeneralConsent
|
||||
const parsed = JSON.parse(recX?.value || '{}')
|
||||
return parsed?.responsible || '-'
|
||||
},
|
||||
informant(rec) {
|
||||
const recX = rec as GeneralConsent
|
||||
const parsed = JSON.parse(recX?.value || '{}')
|
||||
return parsed?.informant || '-'
|
||||
},
|
||||
witness1(rec) {
|
||||
const recX = rec as GeneralConsent
|
||||
const parsed = JSON.parse(recX?.value || '{}')
|
||||
return parsed?.witness1 || '-'
|
||||
},
|
||||
witness2(rec) {
|
||||
const recX = rec as GeneralConsent
|
||||
const parsed = JSON.parse(recX?.value || '{}')
|
||||
return parsed?.witness2 || '-'
|
||||
},
|
||||
action(rec, idx) {
|
||||
const res: RecComponent = {
|
||||
idx,
|
||||
rec: rec as object,
|
||||
component: action,
|
||||
props: {
|
||||
size: 'sm',
|
||||
},
|
||||
}
|
||||
return res
|
||||
},
|
||||
},
|
||||
components: {
|
||||
action(rec, idx) {
|
||||
const res: RecComponent = {
|
||||
idx,
|
||||
rec: rec as object,
|
||||
component: action,
|
||||
props: {
|
||||
size: 'sm',
|
||||
},
|
||||
}
|
||||
return res
|
||||
},
|
||||
} as RecStrFuncComponent,
|
||||
htmls: {} as RecStrFuncUnknown,
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
<script setup lang="ts">
|
||||
import type { PaginationMeta } from '~/components/pub/my-ui/pagination/pagination.type'
|
||||
import PaginationView from '~/components/pub/my-ui/pagination/pagination-view.vue'
|
||||
import { config } from './list.cfg'
|
||||
|
||||
interface Props {
|
||||
data: any[]
|
||||
paginationMeta: PaginationMeta
|
||||
}
|
||||
const props = defineProps<Props>()
|
||||
|
||||
const emit = defineEmits<{
|
||||
pageChange: [page: number]
|
||||
}>()
|
||||
|
||||
function handlePageChange(page: number) {
|
||||
emit('pageChange', page)
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="space-y-4">
|
||||
<PubMyUiDataTable
|
||||
v-bind="config"
|
||||
:rows="data"
|
||||
:skeleton-size="paginationMeta?.pageSize"
|
||||
/>
|
||||
<!-- FIXME: pindahkan ke content/division/list.vue -->
|
||||
<PaginationView
|
||||
:pagination-meta="paginationMeta"
|
||||
@page-change="handlePageChange"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
@@ -0,0 +1,119 @@
|
||||
<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'
|
||||
|
||||
// Types
|
||||
import type { BaseFormData } from '~/schemas/base.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: BaseFormData, resetForm: () => void]
|
||||
cancel: [resetForm: () => void]
|
||||
}>()
|
||||
|
||||
const { defineField, errors, meta } = useForm({
|
||||
validationSchema: props.schema ? toTypedSchema(props.schema) : undefined,
|
||||
initialValues: {
|
||||
code: '',
|
||||
name: '',
|
||||
},
|
||||
})
|
||||
|
||||
const [code, codeAttrs] = defineField('code')
|
||||
const [name, nameAttrs] = defineField('name')
|
||||
|
||||
if (props.values) {
|
||||
if (props.values.code !== undefined) code.value = props.values.code
|
||||
if (props.values.name !== undefined) name.value = props.values.name
|
||||
}
|
||||
|
||||
const resetForm = () => {
|
||||
code.value = ''
|
||||
name.value = ''
|
||||
}
|
||||
|
||||
function onSubmitForm() {
|
||||
const formData = {
|
||||
name: name.value || '',
|
||||
code: code.value || '',
|
||||
}
|
||||
emit('submit', formData, resetForm)
|
||||
}
|
||||
|
||||
function onCancelForm() {
|
||||
emit('cancel', resetForm)
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<form
|
||||
id="form-medicine-group"
|
||||
@submit.prevent
|
||||
>
|
||||
<Block
|
||||
labelSize="thin"
|
||||
class="!mb-2.5 !pt-0 xl:!mb-3"
|
||||
:colCount="1"
|
||||
>
|
||||
<Cell>
|
||||
<Label height="">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,38 @@
|
||||
import type { Config, RecComponent } from '~/components/pub/my-ui/data-table'
|
||||
import { defineAsyncComponent } from 'vue'
|
||||
|
||||
const action = defineAsyncComponent(() => import('~/components/pub/my-ui/data/dropdown-action-ud.vue'))
|
||||
|
||||
export const config: Config = {
|
||||
cols: [{}, {}, { width: 50 }],
|
||||
|
||||
headers: [
|
||||
[
|
||||
{ label: 'Kode' },
|
||||
{ label: 'Nama' },
|
||||
{ label: 'Aksi' },
|
||||
],
|
||||
],
|
||||
|
||||
keys: ['code', 'name', 'action'],
|
||||
|
||||
delKeyNames: [
|
||||
{ key: 'code', label: 'Kode' },
|
||||
{ key: 'name', label: 'Nama' },
|
||||
],
|
||||
|
||||
parses: {},
|
||||
|
||||
components: {
|
||||
action(rec, idx) {
|
||||
const res: RecComponent = {
|
||||
idx,
|
||||
rec: rec as object,
|
||||
component: action,
|
||||
}
|
||||
return res
|
||||
},
|
||||
},
|
||||
|
||||
htmls: {},
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
<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 { config } 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
|
||||
v-bind="config"
|
||||
:rows="data"
|
||||
/>
|
||||
<PaginationView :pagination-meta="paginationMeta" @page-change="handlePageChange" />
|
||||
</div>
|
||||
</template>
|
||||
@@ -18,6 +18,7 @@ interface Props {
|
||||
isReadonly?: boolean
|
||||
medicineGroups?: { value: string; label: string }[]
|
||||
medicineMethods?: { value: string; label: string }[]
|
||||
medicineForms?: { value: string; label: string }[]
|
||||
uoms?: { value: string; label: string }[]
|
||||
}
|
||||
|
||||
@@ -36,6 +37,7 @@ const { defineField, errors, meta } = useForm({
|
||||
name: '',
|
||||
medicineGroup_code: '',
|
||||
medicineMethod_code: '',
|
||||
medicineForm_code: '',
|
||||
uom_code: '',
|
||||
stock: 0,
|
||||
},
|
||||
@@ -45,6 +47,7 @@ const [code, codeAttrs] = defineField('code')
|
||||
const [name, nameAttrs] = defineField('name')
|
||||
const [medicineGroup_code, medicineGroupAttrs] = defineField('medicineGroup_code')
|
||||
const [medicineMethod_code, medicineMethodAttrs] = defineField('medicineMethod_code')
|
||||
const [medicineForm_code, medicineFormAttrs] = defineField('medicineForm_code')
|
||||
const [uom_code, uomAttrs] = defineField('uom_code')
|
||||
const [stock, stockAttrs] = defineField('stock')
|
||||
|
||||
@@ -53,6 +56,7 @@ if (props.values) {
|
||||
if (props.values.name !== undefined) name.value = props.values.name
|
||||
if (props.values.medicineGroup_code !== undefined) medicineGroup_code.value = props.values.medicineGroup_code
|
||||
if (props.values.medicineMethod_code !== undefined) medicineMethod_code.value = props.values.medicineMethod_code
|
||||
if (props.values.medicineForm_code !== undefined) medicineForm_code.value = props.values.medicineForm_code
|
||||
if (props.values.uom_code !== undefined) uom_code.value = props.values.uom_code
|
||||
if (props.values.stock !== undefined) stock.value = props.values.stock
|
||||
}
|
||||
@@ -62,6 +66,7 @@ const resetForm = () => {
|
||||
name.value = ''
|
||||
medicineGroup_code.value = ''
|
||||
medicineMethod_code.value = ''
|
||||
medicineForm_code.value = '',
|
||||
uom_code.value = ''
|
||||
stock.value = 0
|
||||
}
|
||||
@@ -72,6 +77,7 @@ function onSubmitForm() {
|
||||
name: name.value || '',
|
||||
medicineGroup_code: medicineGroup_code.value || '',
|
||||
medicineMethod_code: medicineMethod_code.value || '',
|
||||
medicineForm_code: medicineForm_code.value || '',
|
||||
uom_code: uom_code.value || '',
|
||||
stock: stock.value || 0,
|
||||
}
|
||||
@@ -138,6 +144,20 @@ function onCancelForm() {
|
||||
/>
|
||||
</Field>
|
||||
</Cell>
|
||||
<Cell>
|
||||
<Label height="compact">Sediaan Obat</Label>
|
||||
<Field :errMessage="errors.medicineForm_code">
|
||||
<Select
|
||||
id="medicineForm_code"
|
||||
v-model="medicineForm_code"
|
||||
icon-name="i-lucide-chevron-down"
|
||||
placeholder="Pilih metode pemberian"
|
||||
v-bind="medicineFormAttrs"
|
||||
:items="props.medicineForms || []"
|
||||
:disabled="isLoading || isReadonly"
|
||||
/>
|
||||
</Field>
|
||||
</Cell>
|
||||
<Cell>
|
||||
<Label>Satuan</Label>
|
||||
<Field :errMessage="errors.uom_code">
|
||||
|
||||
@@ -15,12 +15,13 @@ export const config: Config = {
|
||||
{ label: 'Golongan' },
|
||||
{ label: 'Metode Pemberian' },
|
||||
{ label: 'Satuan' },
|
||||
{ label: 'Sediaan' },
|
||||
{ label: 'Stok' },
|
||||
{ label: 'Aksi' },
|
||||
],
|
||||
],
|
||||
|
||||
keys: ['code', 'name', 'group', 'method', 'unit', 'stock', 'action'],
|
||||
keys: ['code', 'name', 'group', 'method', 'unit', 'form', 'stock', 'action'],
|
||||
|
||||
delKeyNames: [
|
||||
{ key: 'code', label: 'Kode' },
|
||||
@@ -37,6 +38,9 @@ export const config: Config = {
|
||||
unit: (rec: unknown): unknown => {
|
||||
return (rec as SmallDetailDto).uom?.name || '-'
|
||||
},
|
||||
form: (rec: unknown): unknown => {
|
||||
return (rec as SmallDetailDto).medicineForm?.name || '-'
|
||||
},
|
||||
},
|
||||
|
||||
components: {
|
||||
|
||||
@@ -11,16 +11,17 @@ export const config: Config = {
|
||||
headers: [
|
||||
[
|
||||
{ label: 'Nama' },
|
||||
{ label: 'Cara Buat' },
|
||||
{ label: 'Bentuk' },
|
||||
{ label: 'Freq' },
|
||||
{ label: 'Dosis' },
|
||||
{ label: 'Interval' },
|
||||
// { label: 'Interval' },
|
||||
{ label: 'Total' },
|
||||
{ label: '' },
|
||||
],
|
||||
],
|
||||
|
||||
keys: ['name', 'uom_code', 'frequency', 'multiplier', 'interval', 'total', 'action'],
|
||||
keys: ['medicine.name', 'isMix', 'medicine.medicineForm.name', 'frequency', 'dose', 'quantity', 'action'], //
|
||||
|
||||
delKeyNames: [
|
||||
{ key: 'code', label: 'Kode' },
|
||||
@@ -28,17 +29,8 @@ export const config: Config = {
|
||||
],
|
||||
|
||||
parses: {
|
||||
cateogry: (rec: unknown): unknown => {
|
||||
return (rec as SmallDetailDto).medicineCategory?.name || '-'
|
||||
},
|
||||
group: (rec: unknown): unknown => {
|
||||
return (rec as SmallDetailDto).medicineGroup?.name || '-'
|
||||
},
|
||||
method: (rec: unknown): unknown => {
|
||||
return (rec as SmallDetailDto).medicineMethod?.name || '-'
|
||||
},
|
||||
unit: (rec: unknown): unknown => {
|
||||
return (rec as SmallDetailDto).medicineUnit?.name || '-'
|
||||
isMix: (rec: unknown): unknown => {
|
||||
return (rec as SmallDetailDto).isMix ? 'Racikan' : 'Non Racikan'
|
||||
},
|
||||
},
|
||||
|
||||
|
||||
@@ -12,12 +12,11 @@ export const config: Config = {
|
||||
{ label: 'Bentuk' },
|
||||
{ label: 'Freq' },
|
||||
{ label: 'Dosis' },
|
||||
{ label: 'Interval' },
|
||||
{ label: 'Total' },
|
||||
],
|
||||
],
|
||||
|
||||
keys: ['name', 'uom_code', 'frequency', 'multiplier', 'interval', 'total'],
|
||||
keys: ['medicine.name', 'medicine.medicineForm.name', 'frequency', 'dose', 'total'],
|
||||
|
||||
delKeyNames: [
|
||||
{ key: 'code', label: 'Kode' },
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
<script setup lang="ts">
|
||||
import DataTable from '~/components/pub/my-ui/data-table/data-table.vue'
|
||||
|
||||
import type { PrescriptionItem } from '~/models/prescription-item';
|
||||
import { config } from './list.cfg'
|
||||
|
||||
@@ -13,7 +15,7 @@ const emit = defineEmits<{
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<PubMyUiDataTable class="border mb-2 2xl:mb-3"
|
||||
<DataTable class="border mb-2"
|
||||
v-bind="config"
|
||||
:rows="data"
|
||||
/>
|
||||
|
||||
@@ -1,29 +1,36 @@
|
||||
<script setup lang="ts">
|
||||
import { LucidePlus } from 'lucide-vue-next';
|
||||
|
||||
import * as DE from '~/components/pub/my-ui/doc-entry'
|
||||
import Separator from '~/components/pub/ui/separator/Separator.vue';
|
||||
import * as Table from '~/components/pub/ui/table'
|
||||
import Nav from '~/components/pub/my-ui/nav-footer/cl-sa.vue'
|
||||
|
||||
import * as CB from '~/components/pub/my-ui/combobox'
|
||||
|
||||
import { genBase } from '~/models/_base';
|
||||
import { genMedicine } from '~/models/medicine';
|
||||
import { type Medicine, genMedicine } from '~/models/medicine';
|
||||
import type { MedicinemixItem } from '~/models/medicinemix-item';
|
||||
import type { PrescriptionItem } from '~/models/prescription-item';
|
||||
|
||||
const props = defineProps<{
|
||||
data: PrescriptionItem
|
||||
items: MedicinemixItem[]
|
||||
medicines: Medicine[]
|
||||
}>()
|
||||
|
||||
const { medicines } = toRefs(props)
|
||||
const medicineItems = ref<CB.Item[]>([])
|
||||
|
||||
type ClickType = 'close' | 'save'
|
||||
|
||||
const emit = defineEmits<{
|
||||
close: [],
|
||||
save: [data: PrescriptionItem, items: MedicinemixItem[]],
|
||||
'update:searchText': [value: string]
|
||||
}>()
|
||||
|
||||
watch(medicines, (data) => {
|
||||
medicineItems.value = CB.objectsToItems(data, 'code', 'name')
|
||||
})
|
||||
|
||||
function navClick(type: ClickType) {
|
||||
if (type === 'close') {
|
||||
emit('close')
|
||||
@@ -42,33 +49,43 @@ function addItem() {
|
||||
uom_code: '',
|
||||
})
|
||||
}
|
||||
|
||||
function searchMedicineText(value: string) {
|
||||
emit('update:searchText', value)
|
||||
}
|
||||
|
||||
function deleteItem(idx: number) {
|
||||
props.items.splice(idx, 1)
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<DE.Block :colCount="5" :cellFlex="false">
|
||||
<DE.Cell :colSpan="5">
|
||||
<DE.Label>Nama</DE.Label>
|
||||
<DE.Field><Input :value="data.medicineMix?.name" /></DE.Field>
|
||||
<DE.Block :colCount="4" :cellFlex="false">
|
||||
<DE.Cell :colSpan="4">
|
||||
<DE.Label>Nama</DE.Label>
|
||||
<DE.Field>
|
||||
<Input :value="data.medicineMix?.name" />
|
||||
</DE.Field>
|
||||
</DE.Cell>
|
||||
<DE.Cell>
|
||||
<DE.Label>Frequensi</DE.Label>
|
||||
<DE.Field><Input v-model="data.frequency" /></DE.Field>
|
||||
<DE.Label>Frequensi</DE.Label>
|
||||
<DE.Field><Input v-model="data.frequency" /></DE.Field>
|
||||
</DE.Cell>
|
||||
<DE.Cell>
|
||||
<DE.Label>Dosis</DE.Label>
|
||||
<DE.Field><Input v-model="data.dose" /></DE.Field>
|
||||
<DE.Label>Dosis</DE.Label>
|
||||
<DE.Field><Input v-model="data.dose" /></DE.Field>
|
||||
</DE.Cell>
|
||||
<DE.Cell>
|
||||
<DE.Label>Sediaan</DE.Label>
|
||||
<DE.Field><Input :value="data.medicineMix?.uom_code" /></DE.Field>
|
||||
<DE.Label>Sediaan</DE.Label>
|
||||
<DE.Field><Input :value="data.medicineMix?.uom_code" /></DE.Field>
|
||||
</DE.Cell>
|
||||
<DE.Cell>
|
||||
<DE.Label>Total</DE.Label>
|
||||
<DE.Field><Input /></DE.Field>
|
||||
<DE.Label>Total</DE.Label>
|
||||
<DE.Field><Input v-model="data.quantity" /></DE.Field>
|
||||
</DE.Cell>
|
||||
<DE.Cell :colSpan="5">
|
||||
<DE.Label>Cara Pakai</DE.Label>
|
||||
<DE.Field><Input /></DE.Field>
|
||||
<DE.Cell :colSpan="4">
|
||||
<DE.Label>Cara Pakai</DE.Label>
|
||||
<DE.Field><Input v-model="data.usage" /></DE.Field>
|
||||
</DE.Cell>
|
||||
</DE.Block>
|
||||
<div class="text-sm 2xl:text-base font-semibold !mb-3">Daftar Obat</div>
|
||||
@@ -77,20 +94,29 @@ function addItem() {
|
||||
<Table.TableRow>
|
||||
<Table.TableHead>Nama</Table.TableHead>
|
||||
<Table.TableHead class="w-24">Dosis</Table.TableHead>
|
||||
<Table.TableHead class="w-24">Satuan</Table.TableHead>
|
||||
<Table.TableHead class="w-20">..</Table.TableHead>
|
||||
<!-- <Table.TableHead class="w-24">Satuan</Table.TableHead> -->
|
||||
<Table.TableHead class="w-10"></Table.TableHead>
|
||||
</Table.TableRow>
|
||||
</Table.TableHeader>
|
||||
<Table.TableBody class="[&_td]:p-0.6">
|
||||
<Table.TableRow v-if="items.length > 0" v-for="item in items">
|
||||
<Table.TableRow v-if="items.length > 0" v-for="item, idx in items">
|
||||
<Table.TableCell>
|
||||
<Input v-model="item.medicine.name" />
|
||||
<CB.Combobox
|
||||
v-model="data.medicine_code"
|
||||
:items="medicineItems"
|
||||
@update:searchText="searchMedicineText"
|
||||
/>
|
||||
</Table.TableCell>
|
||||
<Table.TableCell>
|
||||
<Input v-model="item.dose" />
|
||||
</Table.TableCell>
|
||||
<Table.TableCell>
|
||||
<!-- <Table.TableCell>
|
||||
<Input />
|
||||
</Table.TableCell> -->
|
||||
<Table.TableCell class="text-center">
|
||||
<Button class="!w-7 !h-7 !p-0 rounded-full" @click="deleteItem(idx)">
|
||||
<Icon name="i-lucide-trash" />
|
||||
</Button>
|
||||
</Table.TableCell>
|
||||
</Table.TableRow>
|
||||
<Table.TableRow v-else>
|
||||
@@ -102,7 +128,7 @@ function addItem() {
|
||||
</Table.Table>
|
||||
<div>
|
||||
<Button @click="addItem">
|
||||
<LucidePlus />
|
||||
<Icon name="i-lucide-plus" class="me-2" />
|
||||
Tambah
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
@@ -2,40 +2,45 @@
|
||||
import * as DE from '~/components/pub/my-ui/doc-entry'
|
||||
import Separator from '~/components/pub/ui/separator/Separator.vue'
|
||||
import Nav from '~/components/pub/my-ui/nav-footer/cl-sa.vue'
|
||||
import * as CB from '~/components/pub/my-ui/combobox'
|
||||
|
||||
import { bigTimeUnitCodes } from '~/lib/constants'
|
||||
// import { bigTimeUnitCodes } from '~/lib/constants'
|
||||
|
||||
import { type Medicine } from '~/models/medicine';
|
||||
import type { PrescriptionItem } from '~/models/prescription-item'
|
||||
|
||||
const props = defineProps<{
|
||||
data: PrescriptionItem
|
||||
medicines: Medicine[]
|
||||
}>()
|
||||
|
||||
const { medicines } = toRefs(props)
|
||||
const medicineItems = ref<CB.Item[]>([])
|
||||
const medicineForm = computed(() => {
|
||||
const medicine = props.medicines.find(m => m.code === props.data.medicine_code)
|
||||
return medicine ? medicine.medicineForm?.name : '--tidak diketahui--'
|
||||
})
|
||||
|
||||
type ClickType = 'close' | 'save'
|
||||
type Item = {
|
||||
value: string
|
||||
label: string
|
||||
}
|
||||
|
||||
const bigTimeUnitCodeItems: Item[] = []
|
||||
|
||||
if(!props.data.intervalUnit_code) {
|
||||
props.data.intervalUnit_code = 'day'
|
||||
}
|
||||
|
||||
Object.keys(bigTimeUnitCodes).forEach((key) => {
|
||||
bigTimeUnitCodeItems.push({
|
||||
value: key,
|
||||
label: bigTimeUnitCodes[key] || '',
|
||||
})
|
||||
})
|
||||
|
||||
|
||||
const emit = defineEmits<{
|
||||
close: [],
|
||||
save: [data: PrescriptionItem],
|
||||
'update:searchText': [value: string]
|
||||
}>()
|
||||
|
||||
watch(medicines, (data) => {
|
||||
medicineItems.value = CB.objectsToItems(data, 'code', 'name')
|
||||
})
|
||||
|
||||
function navClick(type: ClickType) {
|
||||
if (type === 'close') {
|
||||
emit('close')
|
||||
@@ -43,13 +48,23 @@ function navClick(type: ClickType) {
|
||||
emit('save', props.data)
|
||||
}
|
||||
}
|
||||
|
||||
function searchMedicineText(value: string) {
|
||||
emit('update:searchText', value)
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<DE.Block :colCount="5" :cellFlex="false">
|
||||
<DE.Cell :colSpan="5">
|
||||
<DE.Label>Nama</DE.Label>
|
||||
<DE.Field><Input :value="data.medicineMix?.name" /></DE.Field>
|
||||
<DE.Block :colCount="4" :cellFlex="false">
|
||||
<DE.Cell :colSpan="4">
|
||||
<DE.Label>Nama</DE.Label>
|
||||
<DE.Field>
|
||||
<CB.Combobox
|
||||
v-model="data.medicine_code"
|
||||
:items="medicineItems"
|
||||
@update:searchText="searchMedicineText"
|
||||
/>
|
||||
</DE.Field>
|
||||
</DE.Cell>
|
||||
<DE.Cell>
|
||||
<DE.Label>Frequensi</DE.Label>
|
||||
@@ -59,11 +74,7 @@ function navClick(type: ClickType) {
|
||||
<DE.Label>Dosis</DE.Label>
|
||||
<DE.Field><Input type="number" v-model.number="data.dose" /></DE.Field>
|
||||
</DE.Cell>
|
||||
<DE.Cell>
|
||||
<DE.Label>Sediaan</DE.Label>
|
||||
<DE.Field><Input :value="data.medicineMix?.uom_code" readonly /></DE.Field>
|
||||
</DE.Cell>
|
||||
<DE.Cell>
|
||||
<!-- <DE.Cell>
|
||||
<DE.Label>Interval</DE.Label>
|
||||
<DE.Field>
|
||||
<Select
|
||||
@@ -71,16 +82,20 @@ function navClick(type: ClickType) {
|
||||
:items="bigTimeUnitCodeItems"
|
||||
/>
|
||||
</DE.Field>
|
||||
</DE.Cell>
|
||||
</DE.Cell> -->
|
||||
<DE.Cell>
|
||||
<DE.Label>Total</DE.Label>
|
||||
<DE.Field>
|
||||
<Input v-model="data.quantity" />
|
||||
<Input type="number" v-model="data.quantity" />
|
||||
</DE.Field>
|
||||
</DE.Cell>
|
||||
<DE.Cell :colSpan="5">
|
||||
<DE.Cell>
|
||||
<DE.Label>Sediaan</DE.Label>
|
||||
<DE.Field><Input :value="medicineForm" readonly /></DE.Field>
|
||||
</DE.Cell>
|
||||
<DE.Cell :colSpan="4">
|
||||
<DE.Label>Cara Pakai</DE.Label>
|
||||
<DE.Field><Input /></DE.Field>
|
||||
<DE.Field><Input v-model="data.usage" /></DE.Field>
|
||||
</DE.Cell>
|
||||
</DE.Block>
|
||||
<Separator class="my-5" />
|
||||
|
||||
@@ -13,7 +13,7 @@ const props = defineProps<{
|
||||
Order {{ data.issuedAt?.substring(0, 10) || data.createdAt?.substring(0, 10) }} - {{ data.status_code }}
|
||||
</div>
|
||||
<div class="max-w-[1000px]">
|
||||
<DE.Block mode="preview" :col-count=5 class="!mb-3">
|
||||
<DE.Block mode="preview" label-size="sm" :col-count=5 class="!mb-3">
|
||||
<DE.Cell :col-span="2">
|
||||
<DE.Label class="font-semibold">DPJP</DE.Label>
|
||||
<DE.Field>
|
||||
|
||||
@@ -1,17 +1,25 @@
|
||||
<script setup lang="ts">
|
||||
import type { Prescription } from '~/models/prescription';
|
||||
|
||||
defineProps<{
|
||||
data: Prescription
|
||||
}>()
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="md:grid md:grid-cols-2 font-semibold">
|
||||
<div class="md:grid md:grid-cols-2">
|
||||
<div class="md:pe-10">
|
||||
<PubMyUiDocEntryBlock>
|
||||
<PubMyUiDocEntryCell>
|
||||
<PubMyUiDocEntryLabel>Tgl Order</PubMyUiDocEntryLabel>
|
||||
<PubMyUiDocEntryField>
|
||||
<Input />
|
||||
<Input :value="data.issuedAt || data.createdAt?.substring(0, 10)" readonly />
|
||||
</PubMyUiDocEntryField>
|
||||
</PubMyUiDocEntryCell>
|
||||
<PubMyUiDocEntryCell>
|
||||
<PubMyUiDocEntryLabel>Status</PubMyUiDocEntryLabel>
|
||||
<PubMyUiDocEntryField>
|
||||
<Input />
|
||||
<Input v-model="data.status_code" readonly />
|
||||
</PubMyUiDocEntryField>
|
||||
</PubMyUiDocEntryCell>
|
||||
</PubMyUiDocEntryBlock>
|
||||
@@ -21,16 +29,22 @@
|
||||
<PubMyUiDocEntryCell>
|
||||
<PubMyUiDocEntryLabel position="dynamic">DPJP</PubMyUiDocEntryLabel>
|
||||
<PubMyUiDocEntryField>
|
||||
<Input />
|
||||
<Input v-model="data.doctor.employee.person.name" readonly />
|
||||
</PubMyUiDocEntryField>
|
||||
</PubMyUiDocEntryCell>
|
||||
<PubMyUiDocEntryCell>
|
||||
<PubMyUiDocEntryLabel position="dynamic">PPDS</PubMyUiDocEntryLabel>
|
||||
<PubMyUiDocEntryField>
|
||||
<Input />
|
||||
<Input value="......" readonly />
|
||||
</PubMyUiDocEntryField>
|
||||
</PubMyUiDocEntryCell>
|
||||
</PubMyUiDocEntryBlock>
|
||||
</div>
|
||||
</div>
|
||||
<!-- <div class="">
|
||||
<Button>
|
||||
<Icon name="i-lucide-check" />
|
||||
Simpan
|
||||
</Button>
|
||||
</div> -->
|
||||
</template>
|
||||
|
||||
@@ -0,0 +1,86 @@
|
||||
<script setup lang="ts">
|
||||
import * as Table from '~/components/pub/ui/table'
|
||||
import type { PaginationMeta } from '~/components/pub/my-ui/pagination/pagination.type'
|
||||
import Nav from '~/components/pub/my-ui/nav-footer/ca-ed-su.vue'
|
||||
|
||||
import type { Prescription } from '~/models/prescription';
|
||||
|
||||
interface Props {
|
||||
data: Prescription[]
|
||||
paginationMeta: PaginationMeta
|
||||
}
|
||||
const props = defineProps<Props>()
|
||||
|
||||
const emit = defineEmits<{
|
||||
cancel: [data: any]
|
||||
edit: [data: any],
|
||||
submit: [data: any]
|
||||
}>()
|
||||
|
||||
function navClick(type: 'cancel' | 'edit' | 'submit', data: Prescription): void {
|
||||
if (type === 'cancel') {
|
||||
emit('cancel', data)
|
||||
} else if (type === 'edit') {
|
||||
emit('edit', data)
|
||||
} else if (type === 'submit') {
|
||||
emit('submit', data)
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div v-if="data.length == 0" class="p-10 text-center">
|
||||
<div class="mb-4 xl:mb-5">Belum Ada Data</div>
|
||||
<div>
|
||||
<Button>
|
||||
<Icon name="i-lucide-plus" class="me-2 align-middle" />
|
||||
Tambah Order
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
<Table.Table>
|
||||
<Table.TableHeader>
|
||||
<Table.TableRow>
|
||||
<Table.TableHead class="w-28">Tgl Order</Table.TableHead>
|
||||
<Table.TableHead>DPJP</Table.TableHead>
|
||||
<Table.TableHead>PPDS</Table.TableHead>
|
||||
<Table.TableHead>Jenis Obat</Table.TableHead>
|
||||
<Table.TableHead class="text-center">Status</Table.TableHead>
|
||||
<Table.TableHead class="w-20"></Table.TableHead>
|
||||
</Table.TableRow>
|
||||
</Table.TableHeader>
|
||||
<Table.TableBody>
|
||||
<Table.TableRow v-for="item, idx in data">
|
||||
<Table.TableCell>
|
||||
{{ item.issuedAt?.substring(0, 10) || item.createdAt?.substring(0, 10) }}
|
||||
</Table.TableCell>
|
||||
<Table.TableCell>
|
||||
{{ item.doctor?.employee?.person?.name || '-' }}
|
||||
</Table.TableCell>
|
||||
<Table.TableCell>
|
||||
</Table.TableCell>
|
||||
<Table.TableCell>
|
||||
<div>
|
||||
Racikan: {{ item.items.filter(function(element){ return element.isMix}).length }}
|
||||
</div>
|
||||
<div>
|
||||
Non Racikan: {{ item.items.filter(function(element){ return !element.isMix}).length }}
|
||||
</div>
|
||||
</Table.TableCell>
|
||||
<Table.TableCell class="text-center">
|
||||
{{ item.status_code }}
|
||||
</Table.TableCell>
|
||||
<Table.TableCell class="text-end">
|
||||
<Nav
|
||||
v-if="item.status_code == 'new'"
|
||||
:small-mode="true"
|
||||
:default-class="'flex gap-1'"
|
||||
@click="(type) => { navClick(type, item) }"
|
||||
/>
|
||||
</Table.TableCell>
|
||||
</Table.TableRow>
|
||||
</Table.TableBody>
|
||||
</Table.Table>
|
||||
<template v-for="item, idx in data">
|
||||
</template>
|
||||
</template>
|
||||
+1
-2
@@ -5,7 +5,6 @@ import Nav from '~/components/pub/my-ui/nav-footer/ca-ed-su.vue'
|
||||
|
||||
import type { Prescription } from '~/models/prescription';
|
||||
import PrescriptionItem from '~/components/app/prescription-item/list.vue';
|
||||
import { add } from 'date-fns';
|
||||
|
||||
interface Props {
|
||||
data: Prescription[]
|
||||
@@ -66,7 +65,7 @@ function navClick(type: 'cancel' | 'edit' | 'submit', data: Prescription): void
|
||||
/>
|
||||
</div>
|
||||
</DE.Block>
|
||||
<PrescriptionItem :data="item.items || []" @click="console.log('click')" class="mb-10" />
|
||||
<PrescriptionItem :data="item.items || []" class="mb-10" />
|
||||
<!-- <div v-if="idx < data.length - 1" class="my-8 -mx-4 border-t border-t-slate-300" /> -->
|
||||
</template>
|
||||
</template>
|
||||
@@ -1,7 +1,5 @@
|
||||
<script setup lang="ts">
|
||||
// import { Block, Cell } from '~/components/pub/my-ui/doc-entry/index'
|
||||
// import Block from '~/components/pub/my-ui/doc-entry/block.vue'
|
||||
// import Cell from '~/components/pub/my-ui/doc-entry/cell.vue'
|
||||
import * as DE from '~/components/pub/my-ui/doc-entry';
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@@ -17,40 +15,40 @@
|
||||
<Separator class="my-5" />
|
||||
<div class="md:grid md:grid-cols-2 font-semibold">
|
||||
<div>
|
||||
<PubCustomUiDocEntryBlock mode="preview">
|
||||
<PubCustomUiDocEntryCell>
|
||||
<PubCustomUiDocEntryLabel>Order #1</PubCustomUiDocEntryLabel>
|
||||
<PubCustomUiDocEntryColon />
|
||||
<PubCustomUiDocEntryField>
|
||||
<DE.Block mode="preview">
|
||||
<DE.Cell>
|
||||
<DE.Label>Order #1</DE.Label>
|
||||
<DE.Colon />
|
||||
<DE.Field>
|
||||
2025-01-01
|
||||
</PubCustomUiDocEntryField>
|
||||
</PubCustomUiDocEntryCell>
|
||||
<PubCustomUiDocEntryCell>
|
||||
<PubCustomUiDocEntryLabel>Status</PubCustomUiDocEntryLabel>
|
||||
<PubCustomUiDocEntryColon />
|
||||
<PubCustomUiDocEntryField>
|
||||
</DE.Field>
|
||||
</DE.Cell>
|
||||
<DE.Cell>
|
||||
<DE.Label>Status</DE.Label>
|
||||
<DE.Colon />
|
||||
<DE.Field>
|
||||
Status
|
||||
</PubCustomUiDocEntryField>
|
||||
</PubCustomUiDocEntryCell>
|
||||
</PubCustomUiDocEntryBlock>
|
||||
</DE.Field>
|
||||
</DE.Cell>
|
||||
</DE.Block>
|
||||
</div>
|
||||
<div>
|
||||
<PubCustomUiDocEntryBlock mode="preview">
|
||||
<PubCustomUiDocEntryCell>
|
||||
<PubCustomUiDocEntryLabel>DPJP</PubCustomUiDocEntryLabel>
|
||||
<PubCustomUiDocEntryColon />
|
||||
<PubCustomUiDocEntryField>
|
||||
<DE.Block mode="preview">
|
||||
<DE.Cell>
|
||||
<DE.Label>DPJP</DE.Label>
|
||||
<DE.Colon />
|
||||
<DE.Field>
|
||||
Nama Dokter
|
||||
</PubCustomUiDocEntryField>
|
||||
</PubCustomUiDocEntryCell>
|
||||
<PubCustomUiDocEntryCell>
|
||||
<PubCustomUiDocEntryLabel>PPDS</PubCustomUiDocEntryLabel>
|
||||
<PubCustomUiDocEntryColon />
|
||||
<PubCustomUiDocEntryField>
|
||||
</DE.Field>
|
||||
</DE.Cell>
|
||||
<DE.Cell>
|
||||
<DE.Label>PPDS</DE.Label>
|
||||
<DE.Colon />
|
||||
<DE.Field>
|
||||
Nama PPDS
|
||||
</PubCustomUiDocEntryField>
|
||||
</PubCustomUiDocEntryCell>
|
||||
</PubCustomUiDocEntryBlock>
|
||||
</DE.Field>
|
||||
</DE.Cell>
|
||||
</DE.Block>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
<script setup lang="ts">
|
||||
import type { ListItemDto } from '~/components/pub/my-ui/data/types';
|
||||
|
||||
const props = defineProps<{
|
||||
url: string
|
||||
btnTxt?: string
|
||||
rec: ListItemDto
|
||||
}>()
|
||||
|
||||
function handlePrint() {
|
||||
navigateTo(props.url || 'https://google.com', {external: true,open: { target: "_blank" },});
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Button
|
||||
class="gap-3 items-center border-orange-400 text-orange-400"
|
||||
variant="outline" @click="handlePrint">
|
||||
<Icon name="i-lucide-printer" class="h-4 w-4" />
|
||||
{{ props.btnTxt || 'Lampiran' }}
|
||||
</Button>
|
||||
</template>
|
||||
@@ -0,0 +1,70 @@
|
||||
<script setup lang="ts">
|
||||
import type { FormErrors } from '~/types/error'
|
||||
import Combobox from '~/components/pub/my-ui/combobox/combobox.vue'
|
||||
import { cn, mapToComboboxOptList } from '~/lib/utils'
|
||||
import { occupationCodes } from '~/lib/constants'
|
||||
|
||||
import * as DE from '~/components/pub/my-ui/doc-entry'
|
||||
|
||||
const props = defineProps<{
|
||||
fieldName?: string
|
||||
label?: string
|
||||
placeholder?: string
|
||||
errors?: FormErrors
|
||||
class?: string
|
||||
selectClass?: string
|
||||
fieldGroupClass?: string
|
||||
labelClass?: string
|
||||
isRequired?: boolean
|
||||
}>()
|
||||
|
||||
const {
|
||||
fieldName = 'job',
|
||||
label,
|
||||
placeholder,
|
||||
errors,
|
||||
class: containerClass,
|
||||
fieldGroupClass,
|
||||
labelClass,
|
||||
} = props
|
||||
|
||||
const arrangementTypeOpts = [
|
||||
{ label: 'KRS', value: "krs" },
|
||||
{ label: 'MRS', value: "mrs" },
|
||||
{ label: 'Rujuk Internal', value: "rujukInternal" },
|
||||
{ label: 'Rujuk External', value: "rujukExternal" },
|
||||
{ label: 'Meninggal', value: "meninggal" },
|
||||
]
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<DE.Cell :class="cn('select-field-group', fieldGroupClass, containerClass)">
|
||||
<DE.Label
|
||||
v-show="label"
|
||||
:label-for="fieldName"
|
||||
:class="cn('select-field-label', labelClass)"
|
||||
:is-required="isRequired"
|
||||
>
|
||||
{{ label }}
|
||||
</DE.Label>
|
||||
<DE.Field
|
||||
:id="fieldName"
|
||||
:errors="errors"
|
||||
:class="cn('select-field-wrapper')"
|
||||
>
|
||||
<FormField :name="fieldName" v-slot="{ componentField, value }">
|
||||
<FormItem>
|
||||
<FormControl>
|
||||
<Select
|
||||
v-bind="componentField"
|
||||
:model-value="value"
|
||||
:items="arrangementTypeOpts"
|
||||
:defaultValue='arrangementTypeOpts[0]?.value'
|
||||
/>
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
</FormField>
|
||||
</DE.Field>
|
||||
</DE.Cell>
|
||||
</template>
|
||||
@@ -0,0 +1,70 @@
|
||||
<script setup lang="ts">
|
||||
import type { FormErrors } from '~/types/error'
|
||||
import Combobox from '~/components/pub/my-ui/combobox/combobox.vue'
|
||||
import { cn, mapToComboboxOptList } from '~/lib/utils'
|
||||
import { occupationCodes } from '~/lib/constants'
|
||||
|
||||
import * as DE from '~/components/pub/my-ui/doc-entry'
|
||||
|
||||
const props = defineProps<{
|
||||
fieldName?: string
|
||||
label?: string
|
||||
placeholder?: string
|
||||
errors?: FormErrors
|
||||
class?: string
|
||||
selectClass?: string
|
||||
fieldGroupClass?: string
|
||||
labelClass?: string
|
||||
isRequired?: boolean
|
||||
}>()
|
||||
|
||||
const {
|
||||
fieldName = 'job',
|
||||
label = 'Pekerjaan',
|
||||
placeholder = 'Pilih pekerjaan',
|
||||
errors,
|
||||
class: containerClass,
|
||||
fieldGroupClass,
|
||||
labelClass,
|
||||
} = props
|
||||
|
||||
// Generate job options from constants, sama seperti pola genderCodes
|
||||
const jobOptions = mapToComboboxOptList(occupationCodes)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<DE.Cell :class="cn('select-field-group', fieldGroupClass, containerClass)">
|
||||
<DE.Label
|
||||
:label-for="fieldName"
|
||||
:class="cn('select-field-label', labelClass)"
|
||||
:is-required="isRequired"
|
||||
>
|
||||
{{ label }}
|
||||
</DE.Label>
|
||||
<DE.Field
|
||||
:id="fieldName"
|
||||
:errors="errors"
|
||||
:class="cn('select-field-wrapper')"
|
||||
>
|
||||
<FormField
|
||||
v-slot="{ componentField }"
|
||||
:name="fieldName"
|
||||
>
|
||||
<FormItem>
|
||||
<FormControl>
|
||||
<Combobox
|
||||
class="focus:ring-0 focus:ring-offset-0"
|
||||
:id="fieldName"
|
||||
v-bind="componentField"
|
||||
:items="jobOptions"
|
||||
:placeholder="placeholder"
|
||||
search-placeholder="Cari..."
|
||||
empty-message="Data tidak ditemukan"
|
||||
/>
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
</FormField>
|
||||
</DE.Field>
|
||||
</DE.Cell>
|
||||
</template>
|
||||
@@ -0,0 +1,121 @@
|
||||
<script setup lang="ts">
|
||||
import type { FormErrors } from '~/types/error'
|
||||
import { differenceInDays, differenceInMonths, differenceInYears, parseISO } from 'date-fns'
|
||||
import { Input } from '~/components/pub/ui/input'
|
||||
import { cn } from '~/lib/utils'
|
||||
|
||||
import * as DE from '~/components/pub/my-ui/doc-entry'
|
||||
|
||||
const props = defineProps<{
|
||||
fieldName?: string
|
||||
label?: string
|
||||
placeholder?: string
|
||||
errors?: FormErrors
|
||||
class?: string
|
||||
selectClass?: string
|
||||
fieldGroupClass?: string
|
||||
labelClass?: string
|
||||
isRequired?: boolean
|
||||
isDisabled?: boolean
|
||||
isWithTime?: boolean
|
||||
}>()
|
||||
|
||||
const {
|
||||
fieldName = 'birthDate',
|
||||
label = 'Tanggal Lahir',
|
||||
placeholder = 'Pilih tanggal lahir',
|
||||
errors,
|
||||
class: containerClass,
|
||||
fieldGroupClass,
|
||||
labelClass,
|
||||
isWithTime = false,
|
||||
} = props
|
||||
|
||||
// Reactive variables for age calculation
|
||||
const patientAge = ref<string>('Masukkan tanggal lahir')
|
||||
|
||||
// Function to calculate age with years, months, and days
|
||||
function calculateAge(birthDate: string | Date | undefined): string {
|
||||
if (!birthDate) {
|
||||
return 'Masukkan tanggal lahir'
|
||||
}
|
||||
|
||||
try {
|
||||
let dateObj: Date
|
||||
|
||||
if (typeof birthDate === 'string') {
|
||||
dateObj = parseISO(birthDate)
|
||||
} else {
|
||||
dateObj = birthDate
|
||||
}
|
||||
|
||||
const today = new Date()
|
||||
|
||||
// Calculate years, months, and days
|
||||
const totalYears = differenceInYears(today, dateObj)
|
||||
|
||||
// Calculate remaining months after years
|
||||
const yearsPassed = new Date(dateObj)
|
||||
yearsPassed.setFullYear(yearsPassed.getFullYear() + totalYears)
|
||||
const remainingMonths = differenceInMonths(today, yearsPassed)
|
||||
|
||||
// Calculate remaining days after years and months
|
||||
const monthsPassed = new Date(yearsPassed)
|
||||
monthsPassed.setMonth(monthsPassed.getMonth() + remainingMonths)
|
||||
const remainingDays = differenceInDays(today, monthsPassed)
|
||||
|
||||
// Format the result
|
||||
const parts = []
|
||||
if (totalYears > 0) parts.push(`${totalYears} Tahun`)
|
||||
if (remainingMonths > 0) parts.push(`${remainingMonths} Bulan`)
|
||||
if (remainingDays > 0) parts.push(`${remainingDays} Hari`)
|
||||
|
||||
return parts.length > 0 ? parts.join(' ') : '0 Hari'
|
||||
} catch {
|
||||
return 'Masukkan tanggal lahir'
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<DE.Cell :class="cn('select-field-group', fieldGroupClass, containerClass)">
|
||||
<DE.Label
|
||||
:label-for="fieldName"
|
||||
:class="cn('select-field-label', labelClass)"
|
||||
:is-required="isRequired && !isDisabled"
|
||||
>
|
||||
{{ label }}
|
||||
</DE.Label>
|
||||
<DE.Field
|
||||
:id="fieldName"
|
||||
:errors="errors"
|
||||
:class="cn('select-field-wrapper')"
|
||||
>
|
||||
<FormField
|
||||
v-slot="{ componentField }"
|
||||
:name="fieldName"
|
||||
>
|
||||
<FormItem>
|
||||
<FormControl>
|
||||
<Input
|
||||
id="birthDate"
|
||||
:type="isWithTime ? 'datetime-local' : 'date'"
|
||||
min="1900-01-01"
|
||||
:max="new Date().toISOString().split('T')[0]"
|
||||
v-bind="componentField"
|
||||
:placeholder="placeholder"
|
||||
:disabled="isDisabled"
|
||||
@update:model-value="
|
||||
(value: string | number) => {
|
||||
const dateStr = typeof value === 'number' ? String(value) : value
|
||||
patientAge = calculateAge(dateStr)
|
||||
}
|
||||
"
|
||||
/>
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
</FormField>
|
||||
</DE.Field>
|
||||
</DE.Cell>
|
||||
</template>
|
||||
@@ -0,0 +1,71 @@
|
||||
<script setup lang="ts">
|
||||
import type { FormErrors } from '~/types/error'
|
||||
import Combobox from '~/components/pub/my-ui/combobox/combobox.vue'
|
||||
import { cn, mapToComboboxOptList } from '~/lib/utils'
|
||||
import { occupationCodes } from '~/lib/constants'
|
||||
|
||||
import * as DE from '~/components/pub/my-ui/doc-entry'
|
||||
|
||||
const props = defineProps<{
|
||||
fieldName?: string
|
||||
label?: string
|
||||
placeholder?: string
|
||||
errors?: FormErrors
|
||||
class?: string
|
||||
selectClass?: string
|
||||
fieldGroupClass?: string
|
||||
labelClass?: string
|
||||
isRequired?: boolean
|
||||
}>()
|
||||
|
||||
const {
|
||||
fieldName = 'job',
|
||||
label,
|
||||
placeholder,
|
||||
errors,
|
||||
class: containerClass,
|
||||
fieldGroupClass,
|
||||
labelClass,
|
||||
} = props
|
||||
|
||||
// Generate job options from constants, sama seperti pola genderCodes
|
||||
const jobOptions = mapToComboboxOptList(occupationCodes)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<DE.Cell :class="cn('select-field-group', fieldGroupClass, containerClass)">
|
||||
<DE.Label
|
||||
v-show="label"
|
||||
:label-for="fieldName"
|
||||
:class="cn('select-field-label', labelClass)"
|
||||
:is-required="isRequired"
|
||||
>
|
||||
{{ label }}
|
||||
</DE.Label>
|
||||
<DE.Field
|
||||
:id="fieldName"
|
||||
:errors="errors"
|
||||
:class="cn('select-field-wrapper')"
|
||||
>
|
||||
<FormField
|
||||
v-slot="{ componentField }"
|
||||
:name="fieldName"
|
||||
>
|
||||
<FormItem>
|
||||
<FormControl>
|
||||
<Combobox
|
||||
class="focus:ring-0 focus:ring-offset-0"
|
||||
:id="fieldName"
|
||||
v-bind="componentField"
|
||||
:items="jobOptions"
|
||||
:placeholder="placeholder"
|
||||
search-placeholder="Cari..."
|
||||
empty-message="Data tidak ditemukan"
|
||||
/>
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
</FormField>
|
||||
</DE.Field>
|
||||
</DE.Cell>
|
||||
</template>
|
||||
@@ -0,0 +1,70 @@
|
||||
<script setup lang="ts">
|
||||
import type { FormErrors } from '~/types/error'
|
||||
import Combobox from '~/components/pub/my-ui/combobox/combobox.vue'
|
||||
import { cn, mapToComboboxOptList } from '~/lib/utils'
|
||||
import { occupationCodes } from '~/lib/constants'
|
||||
|
||||
import * as DE from '~/components/pub/my-ui/doc-entry'
|
||||
|
||||
const props = defineProps<{
|
||||
fieldName?: string
|
||||
label?: string
|
||||
placeholder?: string
|
||||
errors?: FormErrors
|
||||
class?: string
|
||||
selectClass?: string
|
||||
fieldGroupClass?: string
|
||||
labelClass?: string
|
||||
isRequired?: boolean
|
||||
}>()
|
||||
|
||||
const {
|
||||
fieldName = 'job',
|
||||
label = 'Pekerjaan',
|
||||
placeholder = 'Pilih pekerjaan',
|
||||
errors,
|
||||
class: containerClass,
|
||||
fieldGroupClass,
|
||||
labelClass,
|
||||
} = props
|
||||
|
||||
// Generate job options from constants, sama seperti pola genderCodes
|
||||
const jobOptions = mapToComboboxOptList(occupationCodes)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<DE.Cell :class="cn('select-field-group', fieldGroupClass, containerClass)">
|
||||
<DE.Label
|
||||
:label-for="fieldName"
|
||||
:class="cn('select-field-label', labelClass)"
|
||||
:is-required="isRequired"
|
||||
>
|
||||
{{ label }}
|
||||
</DE.Label>
|
||||
<DE.Field
|
||||
:id="fieldName"
|
||||
:errors="errors"
|
||||
:class="cn('select-field-wrapper')"
|
||||
>
|
||||
<FormField
|
||||
v-slot="{ componentField }"
|
||||
:name="fieldName"
|
||||
>
|
||||
<FormItem>
|
||||
<FormControl>
|
||||
<Combobox
|
||||
class="focus:ring-0 focus:ring-offset-0"
|
||||
:id="fieldName"
|
||||
v-bind="componentField"
|
||||
:items="jobOptions"
|
||||
:placeholder="placeholder"
|
||||
search-placeholder="Cari..."
|
||||
empty-message="Data tidak ditemukan"
|
||||
/>
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
</FormField>
|
||||
</DE.Field>
|
||||
</DE.Cell>
|
||||
</template>
|
||||
@@ -0,0 +1,70 @@
|
||||
<script setup lang="ts">
|
||||
import type { FormErrors } from '~/types/error'
|
||||
import Combobox from '~/components/pub/my-ui/combobox/combobox.vue'
|
||||
import { cn, mapToComboboxOptList } from '~/lib/utils'
|
||||
import { occupationCodes } from '~/lib/constants'
|
||||
|
||||
import * as DE from '~/components/pub/my-ui/doc-entry'
|
||||
|
||||
const props = defineProps<{
|
||||
fieldName?: string
|
||||
label?: string
|
||||
placeholder?: string
|
||||
errors?: FormErrors
|
||||
class?: string
|
||||
selectClass?: string
|
||||
fieldGroupClass?: string
|
||||
labelClass?: string
|
||||
isRequired?: boolean
|
||||
}>()
|
||||
|
||||
const {
|
||||
fieldName = 'job',
|
||||
label = 'Pekerjaan',
|
||||
placeholder = 'Pilih pekerjaan',
|
||||
errors,
|
||||
class: containerClass,
|
||||
fieldGroupClass,
|
||||
labelClass,
|
||||
} = props
|
||||
|
||||
// Generate job options from constants, sama seperti pola genderCodes
|
||||
const jobOptions = mapToComboboxOptList(occupationCodes)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<DE.Cell :class="cn('select-field-group', fieldGroupClass, containerClass)">
|
||||
<DE.Label
|
||||
:label-for="fieldName"
|
||||
:class="cn('select-field-label', labelClass)"
|
||||
:is-required="isRequired"
|
||||
>
|
||||
{{ label }}
|
||||
</DE.Label>
|
||||
<DE.Field
|
||||
:id="fieldName"
|
||||
:errors="errors"
|
||||
:class="cn('select-field-wrapper')"
|
||||
>
|
||||
<FormField
|
||||
v-slot="{ componentField }"
|
||||
:name="fieldName"
|
||||
>
|
||||
<FormItem>
|
||||
<FormControl>
|
||||
<Combobox
|
||||
class="focus:ring-0 focus:ring-offset-0"
|
||||
:id="fieldName"
|
||||
v-bind="componentField"
|
||||
:items="jobOptions"
|
||||
:placeholder="placeholder"
|
||||
search-placeholder="Cari..."
|
||||
empty-message="Data tidak ditemukan"
|
||||
/>
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
</FormField>
|
||||
</DE.Field>
|
||||
</DE.Cell>
|
||||
</template>
|
||||
@@ -0,0 +1,70 @@
|
||||
<script setup lang="ts">
|
||||
import type { FormErrors } from '~/types/error'
|
||||
import Combobox from '~/components/pub/my-ui/combobox/combobox.vue'
|
||||
import { cn, mapToComboboxOptList } from '~/lib/utils'
|
||||
import { occupationCodes } from '~/lib/constants'
|
||||
|
||||
import * as DE from '~/components/pub/my-ui/doc-entry'
|
||||
|
||||
const props = defineProps<{
|
||||
fieldName?: string
|
||||
label?: string
|
||||
placeholder?: string
|
||||
errors?: FormErrors
|
||||
class?: string
|
||||
selectClass?: string
|
||||
fieldGroupClass?: string
|
||||
labelClass?: string
|
||||
isRequired?: boolean
|
||||
}>()
|
||||
|
||||
const {
|
||||
fieldName = 'job',
|
||||
label = 'Pekerjaan',
|
||||
placeholder = 'Pilih pekerjaan',
|
||||
errors,
|
||||
class: containerClass,
|
||||
fieldGroupClass,
|
||||
labelClass,
|
||||
} = props
|
||||
|
||||
// Generate job options from constants, sama seperti pola genderCodes
|
||||
const jobOptions = mapToComboboxOptList(occupationCodes)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<DE.Cell :class="cn('select-field-group', fieldGroupClass, containerClass)">
|
||||
<DE.Label
|
||||
:label-for="fieldName"
|
||||
:class="cn('select-field-label', labelClass)"
|
||||
:is-required="isRequired"
|
||||
>
|
||||
{{ label }}
|
||||
</DE.Label>
|
||||
<DE.Field
|
||||
:id="fieldName"
|
||||
:errors="errors"
|
||||
:class="cn('select-field-wrapper')"
|
||||
>
|
||||
<FormField
|
||||
v-slot="{ componentField }"
|
||||
:name="fieldName"
|
||||
>
|
||||
<FormItem>
|
||||
<FormControl>
|
||||
<Combobox
|
||||
class="focus:ring-0 focus:ring-offset-0"
|
||||
:id="fieldName"
|
||||
v-bind="componentField"
|
||||
:items="jobOptions"
|
||||
:placeholder="placeholder"
|
||||
search-placeholder="Cari..."
|
||||
empty-message="Data tidak ditemukan"
|
||||
/>
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
</FormField>
|
||||
</DE.Field>
|
||||
</DE.Cell>
|
||||
</template>
|
||||
@@ -0,0 +1,70 @@
|
||||
<script setup lang="ts">
|
||||
import type { FormErrors } from '~/types/error'
|
||||
import Combobox from '~/components/pub/my-ui/combobox/combobox.vue'
|
||||
import { cn, mapToComboboxOptList } from '~/lib/utils'
|
||||
import { occupationCodes } from '~/lib/constants'
|
||||
|
||||
import * as DE from '~/components/pub/my-ui/doc-entry'
|
||||
|
||||
const props = defineProps<{
|
||||
fieldName?: string
|
||||
label?: string
|
||||
placeholder?: string
|
||||
errors?: FormErrors
|
||||
class?: string
|
||||
selectClass?: string
|
||||
fieldGroupClass?: string
|
||||
labelClass?: string
|
||||
isRequired?: boolean
|
||||
}>()
|
||||
|
||||
const {
|
||||
fieldName = 'job',
|
||||
label = 'Pekerjaan',
|
||||
placeholder = 'Pilih pekerjaan',
|
||||
errors,
|
||||
class: containerClass,
|
||||
fieldGroupClass,
|
||||
labelClass,
|
||||
} = props
|
||||
|
||||
// Generate job options from constants, sama seperti pola genderCodes
|
||||
const jobOptions = mapToComboboxOptList(occupationCodes)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<DE.Cell :class="cn('select-field-group', fieldGroupClass, containerClass)">
|
||||
<DE.Label
|
||||
:label-for="fieldName"
|
||||
:class="cn('select-field-label', labelClass)"
|
||||
:is-required="isRequired"
|
||||
>
|
||||
{{ label }}
|
||||
</DE.Label>
|
||||
<DE.Field
|
||||
:id="fieldName"
|
||||
:errors="errors"
|
||||
:class="cn('select-field-wrapper')"
|
||||
>
|
||||
<FormField
|
||||
v-slot="{ componentField }"
|
||||
:name="fieldName"
|
||||
>
|
||||
<FormItem>
|
||||
<FormControl>
|
||||
<Combobox
|
||||
class="focus:ring-0 focus:ring-offset-0"
|
||||
:id="fieldName"
|
||||
v-bind="componentField"
|
||||
:items="jobOptions"
|
||||
:placeholder="placeholder"
|
||||
search-placeholder="Cari..."
|
||||
empty-message="Data tidak ditemukan"
|
||||
/>
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
</FormField>
|
||||
</DE.Field>
|
||||
</DE.Cell>
|
||||
</template>
|
||||
@@ -0,0 +1,70 @@
|
||||
<script setup lang="ts">
|
||||
import type { FormErrors } from '~/types/error'
|
||||
import Combobox from '~/components/pub/my-ui/combobox/combobox.vue'
|
||||
import { cn, mapToComboboxOptList } from '~/lib/utils'
|
||||
import { occupationCodes } from '~/lib/constants'
|
||||
|
||||
import * as DE from '~/components/pub/my-ui/doc-entry'
|
||||
|
||||
const props = defineProps<{
|
||||
fieldName?: string
|
||||
label?: string
|
||||
placeholder?: string
|
||||
errors?: FormErrors
|
||||
class?: string
|
||||
selectClass?: string
|
||||
fieldGroupClass?: string
|
||||
labelClass?: string
|
||||
isRequired?: boolean
|
||||
}>()
|
||||
|
||||
const {
|
||||
fieldName = 'job',
|
||||
label = 'Pekerjaan',
|
||||
placeholder = 'Pilih pekerjaan',
|
||||
errors,
|
||||
class: containerClass,
|
||||
fieldGroupClass,
|
||||
labelClass,
|
||||
} = props
|
||||
|
||||
// Generate job options from constants, sama seperti pola genderCodes
|
||||
const jobOptions = mapToComboboxOptList(occupationCodes)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<DE.Cell :class="cn('select-field-group', fieldGroupClass, containerClass)">
|
||||
<DE.Label
|
||||
:label-for="fieldName"
|
||||
:class="cn('select-field-label', labelClass)"
|
||||
:is-required="isRequired"
|
||||
>
|
||||
{{ label }}
|
||||
</DE.Label>
|
||||
<DE.Field
|
||||
:id="fieldName"
|
||||
:errors="errors"
|
||||
:class="cn('select-field-wrapper')"
|
||||
>
|
||||
<FormField
|
||||
v-slot="{ componentField }"
|
||||
:name="fieldName"
|
||||
>
|
||||
<FormItem>
|
||||
<FormControl>
|
||||
<Combobox
|
||||
class="focus:ring-0 focus:ring-offset-0"
|
||||
:id="fieldName"
|
||||
v-bind="componentField"
|
||||
:items="jobOptions"
|
||||
:placeholder="placeholder"
|
||||
search-placeholder="Cari..."
|
||||
empty-message="Data tidak ditemukan"
|
||||
/>
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
</FormField>
|
||||
</DE.Field>
|
||||
</DE.Cell>
|
||||
</template>
|
||||
@@ -0,0 +1,70 @@
|
||||
<script setup lang="ts">
|
||||
import type { FormErrors } from '~/types/error'
|
||||
import Combobox from '~/components/pub/my-ui/combobox/combobox.vue'
|
||||
import { cn, mapToComboboxOptList } from '~/lib/utils'
|
||||
import { occupationCodes } from '~/lib/constants'
|
||||
|
||||
import * as DE from '~/components/pub/my-ui/doc-entry'
|
||||
|
||||
const props = defineProps<{
|
||||
fieldName?: string
|
||||
label?: string
|
||||
placeholder?: string
|
||||
errors?: FormErrors
|
||||
class?: string
|
||||
selectClass?: string
|
||||
fieldGroupClass?: string
|
||||
labelClass?: string
|
||||
isRequired?: boolean
|
||||
}>()
|
||||
|
||||
const {
|
||||
fieldName = 'job',
|
||||
label = 'Pekerjaan',
|
||||
placeholder = 'Pilih pekerjaan',
|
||||
errors,
|
||||
class: containerClass,
|
||||
fieldGroupClass,
|
||||
labelClass,
|
||||
} = props
|
||||
|
||||
// Generate job options from constants, sama seperti pola genderCodes
|
||||
const jobOptions = mapToComboboxOptList(occupationCodes)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<DE.Cell :class="cn('select-field-group', fieldGroupClass, containerClass)">
|
||||
<DE.Label
|
||||
:label-for="fieldName"
|
||||
:class="cn('select-field-label', labelClass)"
|
||||
:is-required="isRequired"
|
||||
>
|
||||
{{ label }}
|
||||
</DE.Label>
|
||||
<DE.Field
|
||||
:id="fieldName"
|
||||
:errors="errors"
|
||||
:class="cn('select-field-wrapper')"
|
||||
>
|
||||
<FormField
|
||||
v-slot="{ componentField }"
|
||||
:name="fieldName"
|
||||
>
|
||||
<FormItem>
|
||||
<FormControl>
|
||||
<Combobox
|
||||
class="focus:ring-0 focus:ring-offset-0"
|
||||
:id="fieldName"
|
||||
v-bind="componentField"
|
||||
:items="jobOptions"
|
||||
:placeholder="placeholder"
|
||||
search-placeholder="Cari..."
|
||||
empty-message="Data tidak ditemukan"
|
||||
/>
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
</FormField>
|
||||
</DE.Field>
|
||||
</DE.Cell>
|
||||
</template>
|
||||
@@ -0,0 +1,70 @@
|
||||
<script setup lang="ts">
|
||||
import type { FormErrors } from '~/types/error'
|
||||
import Combobox from '~/components/pub/my-ui/combobox/combobox.vue'
|
||||
import { cn, mapToComboboxOptList } from '~/lib/utils'
|
||||
import { occupationCodes } from '~/lib/constants'
|
||||
|
||||
import * as DE from '~/components/pub/my-ui/doc-entry'
|
||||
|
||||
const props = defineProps<{
|
||||
fieldName?: string
|
||||
label?: string
|
||||
placeholder?: string
|
||||
errors?: FormErrors
|
||||
class?: string
|
||||
selectClass?: string
|
||||
fieldGroupClass?: string
|
||||
labelClass?: string
|
||||
isRequired?: boolean
|
||||
}>()
|
||||
|
||||
const {
|
||||
fieldName = 'job',
|
||||
label = 'Pekerjaan',
|
||||
placeholder = 'Pilih pekerjaan',
|
||||
errors,
|
||||
class: containerClass,
|
||||
fieldGroupClass,
|
||||
labelClass,
|
||||
} = props
|
||||
|
||||
// Generate job options from constants, sama seperti pola genderCodes
|
||||
const jobOptions = mapToComboboxOptList(occupationCodes)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<DE.Cell :class="cn('select-field-group', fieldGroupClass, containerClass)">
|
||||
<DE.Label
|
||||
:label-for="fieldName"
|
||||
:class="cn('select-field-label', labelClass)"
|
||||
:is-required="isRequired"
|
||||
>
|
||||
{{ label }}
|
||||
</DE.Label>
|
||||
<DE.Field
|
||||
:id="fieldName"
|
||||
:errors="errors"
|
||||
:class="cn('select-field-wrapper')"
|
||||
>
|
||||
<FormField
|
||||
v-slot="{ componentField }"
|
||||
:name="fieldName"
|
||||
>
|
||||
<FormItem>
|
||||
<FormControl>
|
||||
<Combobox
|
||||
class="focus:ring-0 focus:ring-offset-0"
|
||||
:id="fieldName"
|
||||
v-bind="componentField"
|
||||
:items="jobOptions"
|
||||
:placeholder="placeholder"
|
||||
search-placeholder="Cari..."
|
||||
empty-message="Data tidak ditemukan"
|
||||
/>
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
</FormField>
|
||||
</DE.Field>
|
||||
</DE.Cell>
|
||||
</template>
|
||||
@@ -0,0 +1,70 @@
|
||||
<script setup lang="ts">
|
||||
import type { FormErrors } from '~/types/error'
|
||||
import Combobox from '~/components/pub/my-ui/combobox/combobox.vue'
|
||||
import { cn, mapToComboboxOptList } from '~/lib/utils'
|
||||
import { occupationCodes } from '~/lib/constants'
|
||||
|
||||
import * as DE from '~/components/pub/my-ui/doc-entry'
|
||||
|
||||
const props = defineProps<{
|
||||
fieldName?: string
|
||||
label?: string
|
||||
placeholder?: string
|
||||
errors?: FormErrors
|
||||
class?: string
|
||||
selectClass?: string
|
||||
fieldGroupClass?: string
|
||||
labelClass?: string
|
||||
isRequired?: boolean
|
||||
}>()
|
||||
|
||||
const {
|
||||
fieldName = 'job',
|
||||
label = 'Pekerjaan',
|
||||
placeholder = 'Pilih pekerjaan',
|
||||
errors,
|
||||
class: containerClass,
|
||||
fieldGroupClass,
|
||||
labelClass,
|
||||
} = props
|
||||
|
||||
// Generate job options from constants, sama seperti pola genderCodes
|
||||
const jobOptions = mapToComboboxOptList(occupationCodes)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<DE.Cell :class="cn('select-field-group', fieldGroupClass, containerClass)">
|
||||
<DE.Label
|
||||
:label-for="fieldName"
|
||||
:class="cn('select-field-label', labelClass)"
|
||||
:is-required="isRequired"
|
||||
>
|
||||
{{ label }}
|
||||
</DE.Label>
|
||||
<DE.Field
|
||||
:id="fieldName"
|
||||
:errors="errors"
|
||||
:class="cn('select-field-wrapper')"
|
||||
>
|
||||
<FormField
|
||||
v-slot="{ componentField }"
|
||||
:name="fieldName"
|
||||
>
|
||||
<FormItem>
|
||||
<FormControl>
|
||||
<Combobox
|
||||
class="focus:ring-0 focus:ring-offset-0"
|
||||
:id="fieldName"
|
||||
v-bind="componentField"
|
||||
:items="jobOptions"
|
||||
:placeholder="placeholder"
|
||||
search-placeholder="Cari..."
|
||||
empty-message="Data tidak ditemukan"
|
||||
/>
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
</FormField>
|
||||
</DE.Field>
|
||||
</DE.Cell>
|
||||
</template>
|
||||
@@ -0,0 +1,70 @@
|
||||
<script setup lang="ts">
|
||||
import type { FormErrors } from '~/types/error'
|
||||
import Combobox from '~/components/pub/my-ui/combobox/combobox.vue'
|
||||
import { cn, mapToComboboxOptList } from '~/lib/utils'
|
||||
import { occupationCodes } from '~/lib/constants'
|
||||
|
||||
import * as DE from '~/components/pub/my-ui/doc-entry'
|
||||
|
||||
const props = defineProps<{
|
||||
fieldName?: string
|
||||
label?: string
|
||||
placeholder?: string
|
||||
errors?: FormErrors
|
||||
class?: string
|
||||
selectClass?: string
|
||||
fieldGroupClass?: string
|
||||
labelClass?: string
|
||||
isRequired?: boolean
|
||||
}>()
|
||||
|
||||
const {
|
||||
fieldName = 'job',
|
||||
label = 'Pekerjaan',
|
||||
placeholder = 'Pilih pekerjaan',
|
||||
errors,
|
||||
class: containerClass,
|
||||
fieldGroupClass,
|
||||
labelClass,
|
||||
} = props
|
||||
|
||||
// Generate job options from constants, sama seperti pola genderCodes
|
||||
const jobOptions = mapToComboboxOptList(occupationCodes)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<DE.Cell :class="cn('select-field-group', fieldGroupClass, containerClass)">
|
||||
<DE.Label
|
||||
:label-for="fieldName"
|
||||
:class="cn('select-field-label', labelClass)"
|
||||
:is-required="isRequired"
|
||||
>
|
||||
{{ label }}
|
||||
</DE.Label>
|
||||
<DE.Field
|
||||
:id="fieldName"
|
||||
:errors="errors"
|
||||
:class="cn('select-field-wrapper')"
|
||||
>
|
||||
<FormField
|
||||
v-slot="{ componentField }"
|
||||
:name="fieldName"
|
||||
>
|
||||
<FormItem>
|
||||
<FormControl>
|
||||
<Combobox
|
||||
class="focus:ring-0 focus:ring-offset-0"
|
||||
:id="fieldName"
|
||||
v-bind="componentField"
|
||||
:items="jobOptions"
|
||||
:placeholder="placeholder"
|
||||
search-placeholder="Cari..."
|
||||
empty-message="Data tidak ditemukan"
|
||||
/>
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
</FormField>
|
||||
</DE.Field>
|
||||
</DE.Cell>
|
||||
</template>
|
||||
@@ -0,0 +1,70 @@
|
||||
<script setup lang="ts">
|
||||
import type { FormErrors } from '~/types/error'
|
||||
import Combobox from '~/components/pub/my-ui/combobox/combobox.vue'
|
||||
import { cn, mapToComboboxOptList } from '~/lib/utils'
|
||||
import { occupationCodes } from '~/lib/constants'
|
||||
|
||||
import * as DE from '~/components/pub/my-ui/doc-entry'
|
||||
|
||||
const props = defineProps<{
|
||||
fieldName?: string
|
||||
label?: string
|
||||
placeholder?: string
|
||||
errors?: FormErrors
|
||||
class?: string
|
||||
selectClass?: string
|
||||
fieldGroupClass?: string
|
||||
labelClass?: string
|
||||
isRequired?: boolean
|
||||
}>()
|
||||
|
||||
const {
|
||||
fieldName = 'job',
|
||||
label = 'Pekerjaan',
|
||||
placeholder = 'Pilih pekerjaan',
|
||||
errors,
|
||||
class: containerClass,
|
||||
fieldGroupClass,
|
||||
labelClass,
|
||||
} = props
|
||||
|
||||
// Generate job options from constants, sama seperti pola genderCodes
|
||||
const jobOptions = mapToComboboxOptList(occupationCodes)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<DE.Cell :class="cn('select-field-group', fieldGroupClass, containerClass)">
|
||||
<DE.Label
|
||||
:label-for="fieldName"
|
||||
:class="cn('select-field-label', labelClass)"
|
||||
:is-required="isRequired"
|
||||
>
|
||||
{{ label }}
|
||||
</DE.Label>
|
||||
<DE.Field
|
||||
:id="fieldName"
|
||||
:errors="errors"
|
||||
:class="cn('select-field-wrapper')"
|
||||
>
|
||||
<FormField
|
||||
v-slot="{ componentField }"
|
||||
:name="fieldName"
|
||||
>
|
||||
<FormItem>
|
||||
<FormControl>
|
||||
<Combobox
|
||||
class="focus:ring-0 focus:ring-offset-0"
|
||||
:id="fieldName"
|
||||
v-bind="componentField"
|
||||
:items="jobOptions"
|
||||
:placeholder="placeholder"
|
||||
search-placeholder="Cari..."
|
||||
empty-message="Data tidak ditemukan"
|
||||
/>
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
</FormField>
|
||||
</DE.Field>
|
||||
</DE.Cell>
|
||||
</template>
|
||||
@@ -0,0 +1,71 @@
|
||||
<script setup lang="ts">
|
||||
import type { FormErrors } from '~/types/error'
|
||||
import Combobox from '~/components/pub/my-ui/combobox/combobox.vue'
|
||||
import { cn, mapToComboboxOptList } from '~/lib/utils'
|
||||
import { occupationCodes } from '~/lib/constants'
|
||||
|
||||
import * as DE from '~/components/pub/my-ui/doc-entry'
|
||||
|
||||
const props = defineProps<{
|
||||
fieldName?: string
|
||||
label?: string
|
||||
placeholder?: string
|
||||
errors?: FormErrors
|
||||
class?: string
|
||||
selectClass?: string
|
||||
fieldGroupClass?: string
|
||||
labelClass?: string
|
||||
isRequired?: boolean
|
||||
}>()
|
||||
|
||||
const {
|
||||
fieldName = 'job',
|
||||
label,
|
||||
placeholder,
|
||||
errors,
|
||||
class: containerClass,
|
||||
fieldGroupClass,
|
||||
labelClass,
|
||||
} = props
|
||||
|
||||
// Generate job options from constants, sama seperti pola genderCodes
|
||||
const jobOptions = mapToComboboxOptList(occupationCodes)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<DE.Cell :class="cn('select-field-group', fieldGroupClass, containerClass)">
|
||||
<DE.Label
|
||||
v-show="label"
|
||||
:label-for="fieldName"
|
||||
:class="cn('select-field-label', labelClass)"
|
||||
:is-required="isRequired"
|
||||
>
|
||||
{{ label }}
|
||||
</DE.Label>
|
||||
<DE.Field
|
||||
:id="fieldName"
|
||||
:errors="errors"
|
||||
:class="cn('select-field-wrapper')"
|
||||
>
|
||||
<FormField
|
||||
v-slot="{ componentField }"
|
||||
:name="fieldName"
|
||||
>
|
||||
<FormItem>
|
||||
<FormControl>
|
||||
<Combobox
|
||||
class="focus:ring-0 focus:ring-offset-0"
|
||||
:id="fieldName"
|
||||
v-bind="componentField"
|
||||
:items="jobOptions"
|
||||
:placeholder="placeholder"
|
||||
search-placeholder="Cari..."
|
||||
empty-message="Data tidak ditemukan"
|
||||
/>
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
</FormField>
|
||||
</DE.Field>
|
||||
</DE.Cell>
|
||||
</template>
|
||||
@@ -0,0 +1,67 @@
|
||||
<script setup lang="ts">
|
||||
import { Badge, type Variants } from '~/components/pub/ui/badge'
|
||||
|
||||
const activeStatusCodes: Record<string, string> = {
|
||||
verified: 'Terverifikasi',
|
||||
validated: 'Tervalidasi',
|
||||
unverified: 'Belum Verifikasi',
|
||||
unvalidated: 'Batal Validasi',
|
||||
}
|
||||
|
||||
const props = defineProps<{
|
||||
rec: any
|
||||
idx?: number
|
||||
}>()
|
||||
|
||||
const statusText = computed(() => {
|
||||
let code: keyof typeof activeStatusCodes = `unverified`
|
||||
switch (props.rec.status_code) {
|
||||
case 1:
|
||||
code = 'verified'
|
||||
break
|
||||
case 2:
|
||||
code = 'validated'
|
||||
break
|
||||
case 3:
|
||||
code = 'unverified'
|
||||
break
|
||||
case 4:
|
||||
code = 'unvalidated'
|
||||
break
|
||||
default:
|
||||
code = 'unverified'
|
||||
break
|
||||
}
|
||||
return activeStatusCodes[code]
|
||||
})
|
||||
|
||||
const badgeVariant = computed(() => {
|
||||
let variant: Variants = `outline`
|
||||
switch (props.rec.status_code) {
|
||||
case 1:
|
||||
variant = 'secondary'
|
||||
break
|
||||
case 2:
|
||||
variant = 'default'
|
||||
break
|
||||
case 3:
|
||||
variant = 'outline'
|
||||
break
|
||||
case 4:
|
||||
variant = 'destructive'
|
||||
break
|
||||
default:
|
||||
variant = 'outline'
|
||||
break
|
||||
}
|
||||
return variant
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="flex justify-center">
|
||||
<Badge :variant="badgeVariant" class="rounded-2xl text-[0.6rem]" >
|
||||
{{ statusText }}
|
||||
</Badge>
|
||||
</div>
|
||||
</template>
|
||||
@@ -0,0 +1,482 @@
|
||||
<script setup lang="ts">
|
||||
import type { FormErrors } from '~/types/error'
|
||||
import { toTypedSchema } from '@vee-validate/zod'
|
||||
import { Form } from '~/components/pub/ui/form'
|
||||
import { FieldArray } from 'vee-validate'
|
||||
import SelectDate from './_common/select-date.vue'
|
||||
import InputBase from '~/components/pub/my-ui/form/input-base.vue'
|
||||
|
||||
import * as DE from '~/components/pub/my-ui/doc-entry'
|
||||
import TextAreaInput from '~/components/pub/my-ui/form/text-area-input.vue'
|
||||
import SelectArrangement from './_common/select-arrangement.vue'
|
||||
import type { ResumeArrangementType } from '~/schemas/resume.schema'
|
||||
import SelectFaskes from './_common/select-faskes.vue'
|
||||
import SelectDeathCause from './_common/select-death-cause.vue'
|
||||
import SelectIcd10 from './_common/select-icd-10.vue'
|
||||
import SelectIcd9 from './_common/select-icd-9.vue'
|
||||
import SelectConciousLevel from './_common/select-concious-level.vue'
|
||||
import SelectPainScale from './_common/select-pain-scale.vue'
|
||||
import SelectNationalProgramService from './_common/select-national-program-service.vue'
|
||||
import SelectNationalProgramServiceStatus from './_common/select-national-program-service-status.vue'
|
||||
import SelectHospitalLeaveCondition from './_common/select-hospital-leave-condition.vue'
|
||||
import SelectHospitalLeaveMethod from './_common/select-hospital-leave-method.vue'
|
||||
|
||||
const props = defineProps<{
|
||||
schema: any
|
||||
initialValues?: any
|
||||
resumeArrangementType: ResumeArrangementType
|
||||
errors?: FormErrors
|
||||
}>()
|
||||
|
||||
const isActionHistoryOpen = inject(`isActionHistoryOpen`) as Ref<boolean>
|
||||
const isConsultationHistoryOpen = inject(`isConsultationHistoryOpen`) as Ref<boolean>
|
||||
const isSupportingHistoryOpen = inject(`isSupportingHistoryOpen`) as Ref<boolean>
|
||||
const isFarmacyHistoryOpen = inject(`isFarmacyHistoryOpen`) as Ref<boolean>
|
||||
const isNationalProgramServiceHistoryOpen = inject(`isNationalProgramServiceHistoryOpen`) as Ref<boolean>
|
||||
const formSchema = toTypedSchema(props.schema)
|
||||
const formRef = ref()
|
||||
|
||||
defineExpose({
|
||||
validate: () => formRef.value?.validate(),
|
||||
resetForm: () => formRef.value?.resetForm(),
|
||||
setValues: (values: any, shouldValidate = true) => formRef.value?.setValues(values, shouldValidate),
|
||||
values: computed(() => formRef.value?.values),
|
||||
})
|
||||
|
||||
const DEFAULT_SECONDARY_DIAGNOSIS_VALUE = {
|
||||
diagnosis: '',
|
||||
icd10: '',
|
||||
diagnosisBasis: '',
|
||||
};
|
||||
const DEFAULT_SECONDARY_ACTION_VALUE = {
|
||||
action: '',
|
||||
icd9: '',
|
||||
actionBasis: '',
|
||||
};
|
||||
const DEFAULT_CONSULTATION_VALUE = {
|
||||
consultation: '',
|
||||
consultationReply: '',
|
||||
};
|
||||
|
||||
const initialFormValues = {
|
||||
secondaryDiagnosis: [DEFAULT_SECONDARY_DIAGNOSIS_VALUE],
|
||||
secondaryOperativeNonOperativeAct: [DEFAULT_SECONDARY_ACTION_VALUE],
|
||||
consultation: [DEFAULT_CONSULTATION_VALUE],
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Form ref="formRef"
|
||||
v-slot="{ values }"
|
||||
as=""
|
||||
keep-values
|
||||
:validation-schema="formSchema"
|
||||
:validate-on-mount="false"
|
||||
validation-mode="onSubmit"
|
||||
:initial-values="initialValues ? initialValues : initialFormValues">
|
||||
|
||||
<!-- Pasien -->
|
||||
<h1 class="mb-3 text-base font-medium">Pemeriksaan Pasien</h1>
|
||||
<DE.Block :col-count="3" :cell-flex="false">
|
||||
<SelectDate field-name="inDate" label="Tanggal Masuk" :errors="errors" :is-disabled="true" />
|
||||
<SelectDate field-name="outDate" label="Tanggal Keluar" :errors="errors" :is-disabled="true" />
|
||||
<InputBase
|
||||
field-name="doctor_id"
|
||||
:is-disabled="true"
|
||||
label="DPJP" placeholder="DPJP"/>
|
||||
</DE.Block>
|
||||
<DE.Block class="" :cell-flex="false">
|
||||
<InputBase
|
||||
class="w-2/3"
|
||||
field-name="first_diagnosis"
|
||||
:is-disabled="true"
|
||||
label="Diagnosis Masuk/Rujukan" placeholder="Diagnosis Masuk/Rujukan"/>
|
||||
</DE.Block>
|
||||
<DE.Block :col-count="3" :cell-flex="false">
|
||||
<TextAreaInput field-name="supplementCheckup"
|
||||
label="Indikasi Rawat Jalan" placeholder="Indikasi Rawat Jalan" :errors="errors" />
|
||||
<TextAreaInput field-name="supplementCheckup"
|
||||
label="Keluhan Utama (Singkat & Menunjang)" placeholder="Keluhan Utama (Singkat & Menunjang)" :errors="errors" />
|
||||
<TextAreaInput field-name="supplementCheckup"
|
||||
label="Pemeriksaan Fisik (Singkat & Menunjang)" placeholder="Pemeriksaan Fisik (Singkat & Menunjang)" :errors="errors" />
|
||||
<TextAreaInput field-name="supplementCheckup"
|
||||
label="Riwayat Penyakit" placeholder="Riwayat Penyakit" :errors="errors" />
|
||||
<TextAreaInput field-name="supplementCheckup"
|
||||
label="Diagnosa Medis" placeholder="Diagnosa Medis" :errors="errors" />
|
||||
</DE.Block>
|
||||
<Separator class="my-4" />
|
||||
|
||||
|
||||
|
||||
<!-- DIAGNOSIS -->
|
||||
<h1 class="mb-3 text-base font-medium">Diagnosa</h1>
|
||||
<h1 class="mb-3 text-base font-medium">Diagnosa Utama</h1>
|
||||
<DE.Block :col-count="2" class="" :cell-flex="false">
|
||||
<InputBase
|
||||
field-name="diagnosis"
|
||||
label="Diagnosa" placeholder="Masukkan Diagnosa"
|
||||
:errors="errors" is-required />
|
||||
<SelectIcd10
|
||||
field-name="primaryDiagnosis"
|
||||
label="ICD 10"
|
||||
placeholder="ICD 10"
|
||||
:errors="errors" is-required />
|
||||
<DE.Cell :col-span="2">
|
||||
<TextAreaInput field-name="supplementCheckup"
|
||||
label="Dasar Diagnosa" placeholder="Masukkan Dasar Diagnosa utama Pasien" :errors="errors" />
|
||||
</DE.Cell>
|
||||
|
||||
|
||||
<DE.Cell :col-span="2">
|
||||
<h1 class="mb-3 text-base font-medium">Diagnosa Sekunder</h1>
|
||||
<div class="w-full rounded-md border bg-gray-50/50 p-4 shadow-sm dark:bg-neutral-950">
|
||||
|
||||
<FieldArray v-slot="{ fields, push, remove }" name="secondaryDiagnosis">
|
||||
<div v-for="(field, idx) in fields" :key="idx" class="flex items-center gap-3 mb-3">
|
||||
<div class="w-full">
|
||||
<h1 class="font-medium">Diagnosa {{ idx + 1 }}</h1>
|
||||
<div class="flex gap-3">
|
||||
<InputBase
|
||||
:field-name="`secondaryDiagnosis[${idx}].diagnosis`"
|
||||
label="Diagnosa" placeholder="Masukkan Diagnosa"
|
||||
:errors="errors" is-required />
|
||||
<SelectIcd10
|
||||
:field-name="`secondaryDiagnosis[${idx}].icd10`"
|
||||
label="ICD 10"
|
||||
placeholder="ICD 10"
|
||||
:errors="errors" is-required />
|
||||
</div>
|
||||
<TextAreaInput :field-name="`secondaryDiagnosis[${idx}].diagnosisBasis`"
|
||||
label="Dasar Diagnosa" placeholder="Masukkan Dasar Diagnosa Pasien" :errors="errors" />
|
||||
</div>
|
||||
<Button v-if="idx !== 0" type="button" variant="destructive" size="sm" @click="remove(idx)">
|
||||
<Icon name="i-lucide-trash-2" class="h-4 w-4" />
|
||||
</Button>
|
||||
</div>
|
||||
<Button type="button" variant="outline"
|
||||
class="w-full rounded-md border border-primary bg-white px-4 py-2 text-primary hover:border-primary hover:bg-primary hover:text-white sm:w-auto sm:text-sm"
|
||||
@click="push(DEFAULT_SECONDARY_DIAGNOSIS_VALUE)">
|
||||
<Icon name="i-lucide-plus" class="mr-2 h-4 w-4 align-middle transition-colors" />
|
||||
Tambah Diagnosis
|
||||
</Button>
|
||||
</FieldArray>
|
||||
</div>
|
||||
</DE.Cell>
|
||||
|
||||
|
||||
|
||||
</DE.Block>
|
||||
<Separator class="my-4" />
|
||||
|
||||
|
||||
|
||||
|
||||
<!-- Tindakan OPERATIF/NON OPERATIF -->
|
||||
<div class="mb-3 flex gap-3 items-center">
|
||||
<h1 class="text-base font-medium">Tindakan Operatif/Non Operatif</h1>
|
||||
<Button variant="ghost"
|
||||
class="gap-1 items-center text-orange-400"
|
||||
@click="isActionHistoryOpen = true">
|
||||
<Icon name="i-lucide-history" class="h-4 w-4" /> Riwayat Tindakan</Button>
|
||||
</div>
|
||||
<h1 class="mb-3 font-normal">Tindakan Operatif/Non Operatif Utama</h1>
|
||||
<DE.Block :col-count="2" class="" :cell-flex="false">
|
||||
<InputBase
|
||||
field-name="diagnosis"
|
||||
label="Tindakan" placeholder="Masukkan Tindakan"
|
||||
:errors="errors" is-required />
|
||||
<SelectIcd9
|
||||
field-name="primaryDiagnosis"
|
||||
label="ICD 9"
|
||||
placeholder="ICD 9"
|
||||
:errors="errors" is-required />
|
||||
<DE.Cell :col-span="2">
|
||||
<TextAreaInput field-name="supplementCheckup"
|
||||
label="Dasar Tindakan" placeholder="Masukkan Dasar Tindakan utama Pasien" :errors="errors" />
|
||||
</DE.Cell>
|
||||
|
||||
<DE.Cell :col-span="2">
|
||||
<h1 class="mb-3 text-base font-medium">Tindakan Lain</h1>
|
||||
<div class="w-full rounded-md border bg-gray-50/50 p-4 shadow-sm dark:bg-neutral-950">
|
||||
|
||||
<FieldArray v-slot="{ fields, push, remove }" name="secondaryOperativeNonOperativeAct">
|
||||
<div v-for="(field, idx) in fields" :key="idx" class="flex items-center gap-3 mb-3">
|
||||
<div class="w-full">
|
||||
<h1 class="font-medium">Tindakan {{ idx + 1 }}</h1>
|
||||
<div class="flex gap-3">
|
||||
<InputBase
|
||||
:field-name="`secondaryOperativeNonOperativeAct[${idx}].action`"
|
||||
label="Tindakan" placeholder="Masukkan Tindakan"
|
||||
:errors="errors" is-required />
|
||||
<SelectIcd10
|
||||
:field-name="`secondaryOperativeNonOperativeAct[${idx}].icd9`"
|
||||
label="ICD 10"
|
||||
placeholder="ICD 10"
|
||||
:errors="errors" is-required />
|
||||
</div>
|
||||
<TextAreaInput :field-name="`secondaryOperativeNonOperativeAct[${idx}].actionBasis`"
|
||||
label="Dasar Tindakan" placeholder="Masukkan Dasar Tindakan Pasien" :errors="errors" />
|
||||
</div>
|
||||
<Button v-if="idx !== 0" type="button" variant="destructive" size="sm" @click="remove(idx)">
|
||||
<Icon name="i-lucide-trash-2" class="h-4 w-4" />
|
||||
</Button>
|
||||
</div>
|
||||
<Button type="button" variant="outline"
|
||||
class="w-full rounded-md border border-primary bg-white px-4 py-2 text-primary hover:border-primary hover:bg-primary hover:text-white sm:w-auto sm:text-sm"
|
||||
@click="push(DEFAULT_SECONDARY_ACTION_VALUE)">
|
||||
<Icon name="i-lucide-plus" class="mr-2 h-4 w-4 align-middle transition-colors" />
|
||||
Tambah Tindakan
|
||||
</Button>
|
||||
</FieldArray>
|
||||
</div>
|
||||
</DE.Cell>
|
||||
|
||||
</DE.Block>
|
||||
<TextAreaInput :field-name="`medicalAction`"
|
||||
label="Tindakan Medis" placeholder="Masukkan Tindakan Medis" :errors="errors" />
|
||||
<Separator class="my-4" />
|
||||
|
||||
|
||||
|
||||
<!-- KONSULTASI -->
|
||||
<div class="mb-3 flex gap-3 items-center">
|
||||
<h1 class="text-base font-medium">Konsultasi</h1>
|
||||
<Button variant="ghost"
|
||||
class="gap-1 items-center text-orange-400"
|
||||
@click="isConsultationHistoryOpen = true">
|
||||
<Icon name="i-lucide-history" class="h-4 w-4" /> Riwayat Konsultasi</Button>
|
||||
</div>
|
||||
<div class="w-full rounded-md border bg-gray-50/50 p-4 shadow-sm dark:bg-neutral-950">
|
||||
<FieldArray v-slot="{ fields, push, remove }" name="consultation">
|
||||
<div v-for="(field, idx) in fields" :key="idx" class="flex items-center gap-3 mb-3">
|
||||
<div class="w-full">
|
||||
<h1 class="font-medium mb-1">Konsultasi {{ idx + 1 }}</h1>
|
||||
<div class="flex gap-3">
|
||||
<TextAreaInput :field-name="`consultation[${idx}].consultation`"
|
||||
label="Konsultasi" placeholder="Masukkan Konsultasi" :errors="errors" />
|
||||
<TextAreaInput :field-name="`consultation[${idx}].consultationReply`"
|
||||
label="Jawaban Konsultasi" placeholder="Masukkan Jawaban Konsultasi" :errors="errors" />
|
||||
</div>
|
||||
</div>
|
||||
<Button v-if="idx !== 0" type="button" variant="destructive" size="sm" @click="remove(idx)">
|
||||
<Icon name="i-lucide-trash-2" class="h-4 w-4" />
|
||||
</Button>
|
||||
</div>
|
||||
<Button type="button" variant="outline"
|
||||
class="w-full rounded-md border border-primary bg-white px-4 py-2 text-primary hover:border-primary hover:bg-primary hover:text-white sm:w-auto sm:text-sm"
|
||||
@click="push(DEFAULT_CONSULTATION_VALUE)">
|
||||
<Icon name="i-lucide-plus" class="mr-2 h-4 w-4 align-middle transition-colors" />
|
||||
Tambah Konsultasi
|
||||
</Button>
|
||||
</FieldArray>
|
||||
</div>
|
||||
<Separator class="my-4" />
|
||||
|
||||
|
||||
|
||||
<!-- DATA PENUNJANG -->
|
||||
<section>
|
||||
<div class="mb-3 flex gap-3 items-center">
|
||||
<h1 class="text-base font-medium">Data Penunjang</h1>
|
||||
<Button variant="ghost"
|
||||
class="gap-1 items-center text-orange-400"
|
||||
@click="isSupportingHistoryOpen = true">
|
||||
<Icon name="i-lucide-history" class="h-4 w-4" /> Riwayat Data Penunjang</Button>
|
||||
</div>
|
||||
<DE.Block class="" :cell-flex="false">
|
||||
<TextAreaInput field-name="supplementCheckup" label="Pemeriksaan Penunjang" placeholder="Masukkan Pemeriksaan Penunjang" :errors="errors" />
|
||||
</DE.Block>
|
||||
</section>
|
||||
<Separator class="my-4" />
|
||||
|
||||
|
||||
|
||||
<!-- DATA Farmasi -->
|
||||
<section>
|
||||
<div class="mb-3 flex gap-3 items-center">
|
||||
<h1 class="text-base font-medium">Data Farmasi</h1>
|
||||
<Button variant="ghost"
|
||||
class="gap-1 items-center text-orange-400"
|
||||
@click="isFarmacyHistoryOpen = true">
|
||||
<Icon name="i-lucide-history" class="h-4 w-4" /> Riwayat Data Farmasi</Button>
|
||||
</div>
|
||||
<DE.Block class="items-end" :col-count="2" :cell-flex="false">
|
||||
<TextAreaInput field-name="supplementCheckup"
|
||||
label="Kelainan Khusus Alergi" placeholder="Masukkan Kelainan Khusus Alergi" :errors="errors" />
|
||||
<TextAreaInput field-name="supplementCheckup"
|
||||
label="Kelainan Lain" placeholder="Masukkan Kelainan Lain" :errors="errors" />
|
||||
<TextAreaInput field-name="supplementCheckup"
|
||||
label="Terapi yang Diberikan (Farmakologi dan Non Farmakologi) Selama Dirawat" placeholder="Masukkan Terapi yang Diberikan (Farmakologi dan Non Farmakologi) Selama Dirawat" :errors="errors" />
|
||||
<TextAreaInput field-name="supplementCheckup"
|
||||
label="Terapi yang Diberikan (Farmakologi dan Non Farmakologi) Waktu Pulang" placeholder="Masukkan Terapi yang Diberikan (Farmakologi dan Non Farmakologi) Waktu Pulang" :errors="errors" />
|
||||
<TextAreaInput field-name="supplementCheckup"
|
||||
label="Instruksi Tindak Lanjut/Anjuran dan Edukasi (Follow Up/Kontrol)" placeholder="Masukkan Instruksi Tindak Lanjut/Anjuran dan Edukasi (Follow Up/Kontrol)" :errors="errors" />
|
||||
</DE.Block>
|
||||
</section>
|
||||
<Separator class="my-4" />
|
||||
|
||||
|
||||
|
||||
<!-- Keadaan Waktu Keluar -->
|
||||
<section>
|
||||
<h1 class="mb-3 font-medium">Keadaan Waktu Keluar</h1>
|
||||
<DE.Block :col-count="4" :cell-flex="false">
|
||||
<InputBase
|
||||
:field-name="`aaaaaaaaaaa`"
|
||||
label="Tekanan Darah Sistol" placeholder="Masukkan Tekanan Darah Sistol"
|
||||
right-label="mmHg" bottom-label="Contoh: 90"
|
||||
:errors="errors" is-required numeric-only />
|
||||
<InputBase
|
||||
:field-name="`aaaaaaaaaaa`"
|
||||
label="Tekanan Darah Diastol" placeholder="Masukkan Tekanan Darah Diastol"
|
||||
right-label="mmHg" bottom-label="Contoh: 60"
|
||||
:errors="errors" is-required numeric-only />
|
||||
<InputBase
|
||||
:field-name="`aaaaaaaaaaa`"
|
||||
label="Pernafasan" placeholder="Masukkan Pernafasan"
|
||||
right-label="kali / menit" bottom-label="Contoh: 20"
|
||||
:errors="errors" is-required numeric-only />
|
||||
<InputBase
|
||||
:field-name="`aaaaaaaaaaa`"
|
||||
label="Denyut Jantung" placeholder="Masukkan Denyut Jantung"
|
||||
right-label="kali / menit" bottom-label="Contoh: 20"
|
||||
:errors="errors" is-required numeric-only />
|
||||
<InputBase
|
||||
:field-name="`aaaaaaaaaaa`"
|
||||
label="Suhu Tubuh" placeholder="Masukkan Suhu Tubuh"
|
||||
right-label="'C" bottom-label="Contoh: 37"
|
||||
:errors="errors" is-required numeric-only />
|
||||
<SelectConciousLevel
|
||||
:field-name="`aaaaaaaaaaa`"
|
||||
label="Tingkat Kesadaran"
|
||||
placeholder="Tingkat Kesadaran"
|
||||
:errors="errors" is-required />
|
||||
<SelectPainScale
|
||||
:field-name="`aaaaaaaaaaa`"
|
||||
label="Skala Nyeri"
|
||||
placeholder="Skala Nyeri"
|
||||
:errors="errors" is-required />
|
||||
</DE.Block>
|
||||
</section>
|
||||
<Separator class="my-4" />
|
||||
|
||||
|
||||
|
||||
<!-- Program Nasional -->
|
||||
<section>
|
||||
<div class="mb-3 flex gap-3 items-center">
|
||||
<h1 class="text-base font-medium">Program Nasional</h1>
|
||||
<Button variant="ghost"
|
||||
class="gap-1 items-center text-orange-400"
|
||||
@click="isNationalProgramServiceHistoryOpen = true">
|
||||
<Icon name="i-lucide-history" class="h-4 w-4" /> Riwayat Program Nasional</Button>
|
||||
</div>
|
||||
<DE.Block :col-count="3" :cell-flex="false">
|
||||
<SelectNationalProgramService
|
||||
:field-name="`aaaaaaaaaaa`"
|
||||
label="Layanan Program Nasional"
|
||||
placeholder="Layanan Program Nasional"
|
||||
:errors="errors" is-required />
|
||||
<SelectNationalProgramServiceStatus
|
||||
:field-name="`aaaaaaaaaaa`"
|
||||
label="Status Layanan Program Nasional"
|
||||
placeholder="Status Layanan Program Nasional"
|
||||
:errors="errors" is-required />
|
||||
</DE.Block>
|
||||
</section>
|
||||
<Separator class="my-4" />
|
||||
|
||||
|
||||
|
||||
<!-- Penatalaksanaan -->
|
||||
<section>
|
||||
<h1 class="mb-3 font-medium">Penatalaksanaan</h1>
|
||||
<DE.Block :col-count="3" :cell-flex="false">
|
||||
<SelectArrangement
|
||||
field-name="arrangement"
|
||||
label="Lanjutan Penatalaksanaan"
|
||||
placeholder="Pilih Arrangement"
|
||||
:errors="errors" />
|
||||
<SelectHospitalLeaveCondition
|
||||
:field-name="`aaaaaaaaaaa`"
|
||||
label="Kondisi Meninggalkan RS"
|
||||
placeholder="Kondisi Meninggalkan RS"
|
||||
:errors="errors" is-required />
|
||||
<SelectHospitalLeaveMethod
|
||||
:field-name="`aaaaaaaaaaa`"
|
||||
label="Cara Keluar RS"
|
||||
placeholder="Cara Keluar RS"
|
||||
:errors="errors" is-required />
|
||||
</DE.Block>
|
||||
</section>
|
||||
|
||||
<DE.Cell :col-span="3"
|
||||
v-show="resumeArrangementType === `mrs`">
|
||||
<TextAreaInput
|
||||
field-name="inpatientIndication"
|
||||
label="Indikasi Rawat Jalan"
|
||||
placeholder="Indikasi Rawat Jalan"
|
||||
:errors="errors" />
|
||||
</DE.Cell>
|
||||
|
||||
<DE.Block :col-count="3" :cell-flex="false">
|
||||
<SelectFaskes
|
||||
v-show="resumeArrangementType === `rujukExternal` "
|
||||
field-name="faskes"
|
||||
label="Faskes"
|
||||
placeholder="Pilih Faskes"
|
||||
:errors="errors"
|
||||
/>
|
||||
<InputBase
|
||||
v-show="resumeArrangementType === `rujukExternal` "
|
||||
field-name="clinic"
|
||||
label="Klinik"
|
||||
placeholder="Masukkan Klinik"
|
||||
:errors="errors"
|
||||
/>
|
||||
|
||||
<SelectDate
|
||||
v-show="resumeArrangementType === `meninggal`"
|
||||
field-name="deathDate"
|
||||
label="Jam Tanggal Meninggal"
|
||||
:errors="errors"
|
||||
:is-with-time="true" />
|
||||
|
||||
<DE.Cell class="mt-2" :col-span="3" v-show="resumeArrangementType === `meninggal`">
|
||||
<div class="w-2/3 rounded-md border bg-gray-50/50 p-4 shadow-sm dark:bg-neutral-950">
|
||||
<h1 class="mb-3 font-medium">Sebab Meninggal</h1>
|
||||
|
||||
<FieldArray v-slot="{ fields, push, remove }" name="deathCause">
|
||||
<div v-for="(field, idx) in fields" :key="idx" class="flex items-center gap-3 mb-3">
|
||||
<SelectDeathCause
|
||||
:field-name="`deathCause[${idx}]`"
|
||||
:errors="errors"
|
||||
/>
|
||||
<Button v-if="idx !== 0" type="button" variant="destructive" size="sm" @click="remove(idx)">
|
||||
<Icon name="i-lucide-trash-2" class="h-4 w-4" />
|
||||
</Button>
|
||||
</div>
|
||||
<Button v-if="fields.length < 3" type="button" variant="outline"
|
||||
class="w-full rounded-md border border-primary bg-white px-4 py-2 text-primary hover:border-primary hover:bg-primary hover:text-white sm:w-auto sm:text-sm"
|
||||
@click="push(``)">
|
||||
<Icon name="i-lucide-plus" class="mr-2 h-4 w-4 align-middle transition-colors" />
|
||||
Tambah Sebab Meninggal
|
||||
</Button>
|
||||
</FieldArray>
|
||||
</div>
|
||||
</DE.Cell>
|
||||
|
||||
<DE.Cell
|
||||
v-show="resumeArrangementType === `meninggal`"
|
||||
:col-span="3">
|
||||
<TextAreaInput
|
||||
field-name="deathCauseDescription"
|
||||
label="Keterangan Sebab Meninggal"
|
||||
placeholder="Keterangan Sebab Meninggal"
|
||||
:errors="errors" />
|
||||
</DE.Cell>
|
||||
|
||||
</DE.Block>
|
||||
|
||||
</Form>
|
||||
</template>
|
||||
@@ -0,0 +1,66 @@
|
||||
<script setup lang="ts">
|
||||
import Dialog from '~/components/pub/my-ui/modal/dialog.vue'
|
||||
import type { PaginationMeta } from '~/components/pub/my-ui/pagination/pagination.type'
|
||||
import PaginationView from '~/components/pub/my-ui/pagination/pagination-view.vue'
|
||||
import { config } from './action-list.cfg'
|
||||
import { cn } from '~/lib/utils'
|
||||
import { CalendarDate, DateFormatter, getLocalTimeZone } from '@internationalized/date'
|
||||
import type { DateRange } from 'radix-vue'
|
||||
import { CalendarIcon } from 'lucide-vue-next'
|
||||
|
||||
interface Props {
|
||||
data: any[]
|
||||
paginationMeta: PaginationMeta
|
||||
dateValue: DateRange
|
||||
}
|
||||
const props = defineProps<Props>()
|
||||
const isModalOpen = inject(`isActionHistoryOpen`) as Ref<boolean>
|
||||
|
||||
const df = new DateFormatter('en-US', { dateStyle: 'medium',})
|
||||
|
||||
const emit = defineEmits<{
|
||||
pageChange: [page: number]
|
||||
'update:dateValue': [value: DateRange]
|
||||
}>()
|
||||
|
||||
function handlePageChange(page: number) {
|
||||
emit('pageChange', page)
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Dialog v-model:open="isModalOpen" title="" size="2xl">
|
||||
<div class="space-y-4">
|
||||
<Popover>
|
||||
<PopoverTrigger as-child>
|
||||
<Button variant="outline" :class="cn('mb-1 w-[280px] justify-start text-left font-normal',
|
||||
!props.dateValue && 'text-muted-foreground')">
|
||||
<CalendarIcon class="mr-2 h-4 w-4" />
|
||||
<template v-if="props.dateValue.start">
|
||||
<template v-if="props.dateValue.end">
|
||||
{{ df.format(props.dateValue.start.toDate(getLocalTimeZone())) }} -
|
||||
{{ df.format(props.dateValue.end.toDate(getLocalTimeZone())) }}
|
||||
</template>
|
||||
|
||||
<template v-else>
|
||||
{{ df.format(props.dateValue.start.toDate(getLocalTimeZone())) }}
|
||||
</template>
|
||||
</template>
|
||||
<template v-else> Pick a date </template>
|
||||
</Button>
|
||||
</PopoverTrigger>
|
||||
<PopoverContent class="w-auto p-0">
|
||||
<RangeCalendar v-model="props.dateValue" initial-focus :number-of-months="2"
|
||||
@update:model-value="(date) => emit('update:dateValue', date)" />
|
||||
</PopoverContent>
|
||||
</Popover>
|
||||
|
||||
<PubMyUiDataTable
|
||||
v-bind="config"
|
||||
:rows="data"
|
||||
:skeleton-size="props.paginationMeta?.pageSize"
|
||||
/>
|
||||
<PaginationView :pagination-meta="props.paginationMeta" @page-change="handlePageChange" />
|
||||
</div>
|
||||
</Dialog>
|
||||
</template>
|
||||
@@ -0,0 +1,94 @@
|
||||
import type { Config } from '~/components/pub/my-ui/data-table'
|
||||
import type { Patient } from '~/models/patient'
|
||||
import { defineAsyncComponent } from 'vue'
|
||||
import { educationCodes, genderCodes } from '~/lib/constants'
|
||||
import { calculateAge } from '~/lib/utils'
|
||||
|
||||
const action = defineAsyncComponent(() => import('~/components/pub/my-ui/data/dropdown-action-dvvp.vue'))
|
||||
|
||||
export const config: Config = {
|
||||
cols: [{width: 140}, {}, {}, {width: 140}, {width: 10},],
|
||||
|
||||
headers: [
|
||||
[
|
||||
{ label: 'Tanggal/Jam' },
|
||||
{ label: 'Dokter' },
|
||||
{ label: 'Tempat Layanan' },
|
||||
{ label: 'Jenis' },
|
||||
{ label: 'Jenis Pemeriksaan' },
|
||||
{ label: 'Tanggal/Jam' },
|
||||
],
|
||||
],
|
||||
|
||||
keys: ['birth_date', 'person.name', 'person.name', 'person.name', 'person.name', 'birth_date',],
|
||||
|
||||
delKeyNames: [
|
||||
{ key: 'code', label: 'Kode' },
|
||||
{ key: 'name', label: 'Nama' },
|
||||
],
|
||||
|
||||
parses: {
|
||||
patientId: (rec: unknown): unknown => {
|
||||
const patient = rec as Patient
|
||||
return patient.number
|
||||
},
|
||||
identity_number: (rec: unknown): unknown => {
|
||||
const { person } = rec as Patient
|
||||
|
||||
if (person.nationality == 'WNA') {
|
||||
return person.passportNumber
|
||||
}
|
||||
|
||||
return person.residentIdentityNumber || '-'
|
||||
},
|
||||
birth_date: (rec: unknown): unknown => {
|
||||
const { person } = rec as Patient
|
||||
|
||||
if (typeof person.birthDate == 'object' && person.birthDate) {
|
||||
return (person.birthDate as Date).toLocaleDateString('id-ID')
|
||||
} else if (typeof person.birthDate == 'string') {
|
||||
return (person.birthDate as string).substring(0, 10)
|
||||
}
|
||||
return person.birthDate
|
||||
},
|
||||
patient_age: (rec: unknown): unknown => {
|
||||
const { person } = rec as Patient
|
||||
return calculateAge(person.birthDate)
|
||||
},
|
||||
gender: (rec: unknown): unknown => {
|
||||
const { person } = rec as Patient
|
||||
|
||||
if (typeof person.gender_code == 'number' && person.gender_code >= 0) {
|
||||
return person.gender_code
|
||||
} else if (typeof person.gender_code === 'string' && person.gender_code) {
|
||||
return genderCodes[person.gender_code] || '-'
|
||||
}
|
||||
return '-'
|
||||
},
|
||||
education: (rec: unknown): unknown => {
|
||||
const { person } = rec as Patient
|
||||
if (typeof person.education_code == 'number' && person.education_code >= 0) {
|
||||
return person.education_code
|
||||
} else if (typeof person.education_code === 'string' && person.education_code) {
|
||||
return educationCodes[person.education_code] || '-'
|
||||
}
|
||||
return '-'
|
||||
},
|
||||
},
|
||||
|
||||
components: {
|
||||
action(rec, idx) {
|
||||
return {
|
||||
idx,
|
||||
rec: rec as object,
|
||||
component: action,
|
||||
}
|
||||
},
|
||||
},
|
||||
|
||||
htmls: {
|
||||
patient_address(_rec) {
|
||||
return '-'
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
<script setup lang="ts">
|
||||
import Dialog from '~/components/pub/my-ui/modal/dialog.vue'
|
||||
import type { PaginationMeta } from '~/components/pub/my-ui/pagination/pagination.type'
|
||||
import PaginationView from '~/components/pub/my-ui/pagination/pagination-view.vue'
|
||||
import { config } from './consultation-list.cfg'
|
||||
import { cn } from '~/lib/utils'
|
||||
import { CalendarDate, DateFormatter, getLocalTimeZone } from '@internationalized/date'
|
||||
import type { DateRange } from 'radix-vue'
|
||||
import { CalendarIcon } from 'lucide-vue-next'
|
||||
|
||||
interface Props {
|
||||
data: any[]
|
||||
paginationMeta: PaginationMeta
|
||||
dateValue: DateRange
|
||||
}
|
||||
const props = defineProps<Props>()
|
||||
const isModalOpen = inject(`isConsultationHistoryOpen`) as Ref<boolean>
|
||||
|
||||
const df = new DateFormatter('en-US', { dateStyle: 'medium',})
|
||||
|
||||
const emit = defineEmits<{
|
||||
pageChange: [page: number]
|
||||
'update:dateValue': [value: DateRange]
|
||||
}>()
|
||||
|
||||
function handlePageChange(page: number) {
|
||||
emit('pageChange', page)
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Dialog v-model:open="isModalOpen" title="" size="2xl">
|
||||
<div class="space-y-4">
|
||||
<Popover>
|
||||
<PopoverTrigger as-child>
|
||||
<Button variant="outline" :class="cn('mb-1 w-[280px] justify-start text-left font-normal',
|
||||
!props.dateValue && 'text-muted-foreground')">
|
||||
<CalendarIcon class="mr-2 h-4 w-4" />
|
||||
<template v-if="props.dateValue.start">
|
||||
<template v-if="props.dateValue.end">
|
||||
{{ df.format(props.dateValue.start.toDate(getLocalTimeZone())) }} -
|
||||
{{ df.format(props.dateValue.end.toDate(getLocalTimeZone())) }}
|
||||
</template>
|
||||
|
||||
<template v-else>
|
||||
{{ df.format(props.dateValue.start.toDate(getLocalTimeZone())) }}
|
||||
</template>
|
||||
</template>
|
||||
<template v-else> Pick a date </template>
|
||||
</Button>
|
||||
</PopoverTrigger>
|
||||
<PopoverContent class="w-auto p-0">
|
||||
<RangeCalendar v-model="props.dateValue" initial-focus :number-of-months="2"
|
||||
@update:model-value="(date) => emit('update:dateValue', date)" />
|
||||
</PopoverContent>
|
||||
</Popover>
|
||||
|
||||
<PubMyUiDataTable
|
||||
v-bind="config"
|
||||
:rows="data"
|
||||
:skeleton-size="props.paginationMeta?.pageSize"
|
||||
/>
|
||||
<PaginationView :pagination-meta="props.paginationMeta" @page-change="handlePageChange" />
|
||||
</div>
|
||||
</Dialog>
|
||||
</template>
|
||||
@@ -0,0 +1,51 @@
|
||||
import type { Config } from '~/components/pub/my-ui/data-table'
|
||||
import type { Patient } from '~/models/patient'
|
||||
import { defineAsyncComponent } from 'vue'
|
||||
|
||||
const lampiranBtn = defineAsyncComponent(() => import('../_common/print-btn.vue'))
|
||||
|
||||
export const config: Config = {
|
||||
cols: [{}, {}, {}, {}, {},],
|
||||
|
||||
headers: [
|
||||
[
|
||||
{ label: 'Tanggal/Jam' },
|
||||
{ label: 'Dokter' },
|
||||
{ label: 'Tempat Layanan' },
|
||||
{ label: 'KSM' },
|
||||
{ label: 'Tanggal/Jam' },
|
||||
{ label: 'Tujuan' },
|
||||
{ label: 'Dokter' },
|
||||
{ label: 'Berkas' },
|
||||
],
|
||||
],
|
||||
|
||||
keys: ['birth_date', 'person.name', 'person.name', 'person.name', 'person.name', 'birth_date','person.name', 'action', ],
|
||||
|
||||
parses: {
|
||||
birth_date: (rec: unknown): unknown => {
|
||||
const { person } = rec as Patient
|
||||
|
||||
if (typeof person.birthDate == 'object' && person.birthDate) {
|
||||
return (person.birthDate as Date).toLocaleDateString('id-ID')
|
||||
} else if (typeof person.birthDate == 'string') {
|
||||
return (person.birthDate as string).substring(0, 10)
|
||||
}
|
||||
return person.birthDate
|
||||
},
|
||||
},
|
||||
|
||||
components: {
|
||||
action(rec, idx) {
|
||||
return {
|
||||
idx,
|
||||
rec: rec as object,
|
||||
component: lampiranBtn,
|
||||
}
|
||||
},
|
||||
},
|
||||
|
||||
htmls: {
|
||||
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
<script setup lang="ts">
|
||||
import Dialog from '~/components/pub/my-ui/modal/dialog.vue'
|
||||
import type { PaginationMeta } from '~/components/pub/my-ui/pagination/pagination.type'
|
||||
import PaginationView from '~/components/pub/my-ui/pagination/pagination-view.vue'
|
||||
import { config } from './farmacy-list.cfg'
|
||||
import { cn } from '~/lib/utils'
|
||||
import { CalendarDate, DateFormatter, getLocalTimeZone } from '@internationalized/date'
|
||||
import type { DateRange } from 'radix-vue'
|
||||
import { CalendarIcon } from 'lucide-vue-next'
|
||||
|
||||
interface Props {
|
||||
data: any[]
|
||||
paginationMeta: PaginationMeta
|
||||
dateValue: DateRange
|
||||
}
|
||||
const props = defineProps<Props>()
|
||||
const isModalOpen = inject(`isFarmacyHistoryOpen`) as Ref<boolean>
|
||||
|
||||
const df = new DateFormatter('en-US', { dateStyle: 'medium',})
|
||||
|
||||
const emit = defineEmits<{
|
||||
pageChange: [page: number]
|
||||
'update:dateValue': [value: DateRange]
|
||||
}>()
|
||||
|
||||
function handlePageChange(page: number) {
|
||||
emit('pageChange', page)
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Dialog v-model:open="isModalOpen" title="" size="2xl">
|
||||
<div class="space-y-4">
|
||||
<Popover>
|
||||
<PopoverTrigger as-child>
|
||||
<Button variant="outline" :class="cn('mb-1 w-[280px] justify-start text-left font-normal',
|
||||
!props.dateValue && 'text-muted-foreground')">
|
||||
<CalendarIcon class="mr-2 h-4 w-4" />
|
||||
<template v-if="props.dateValue.start">
|
||||
<template v-if="props.dateValue.end">
|
||||
{{ df.format(props.dateValue.start.toDate(getLocalTimeZone())) }} -
|
||||
{{ df.format(props.dateValue.end.toDate(getLocalTimeZone())) }}
|
||||
</template>
|
||||
|
||||
<template v-else>
|
||||
{{ df.format(props.dateValue.start.toDate(getLocalTimeZone())) }}
|
||||
</template>
|
||||
</template>
|
||||
<template v-else> Pick a date </template>
|
||||
</Button>
|
||||
</PopoverTrigger>
|
||||
<PopoverContent class="w-auto p-0">
|
||||
<RangeCalendar v-model="props.dateValue" initial-focus :number-of-months="2"
|
||||
@update:model-value="(date) => emit('update:dateValue', date)" />
|
||||
</PopoverContent>
|
||||
</Popover>
|
||||
|
||||
<PubMyUiDataTable
|
||||
v-bind="config"
|
||||
:rows="data"
|
||||
:skeleton-size="props.paginationMeta?.pageSize"
|
||||
/>
|
||||
<PaginationView :pagination-meta="props.paginationMeta" @page-change="handlePageChange" />
|
||||
</div>
|
||||
</Dialog>
|
||||
</template>
|
||||
@@ -0,0 +1,39 @@
|
||||
import type { Config } from '~/components/pub/my-ui/data-table'
|
||||
import type { Patient } from '~/models/patient'
|
||||
|
||||
export const config: Config = {
|
||||
cols: [{}, {}, {}, {}, {},],
|
||||
|
||||
headers: [
|
||||
[
|
||||
{ label: 'Tanggal Order' },
|
||||
{ label: 'No Resep' },
|
||||
{ label: 'Tempat Layanan' },
|
||||
{ label: 'Nama Obat' },
|
||||
{ label: 'Tanggal Disetujui' },
|
||||
],
|
||||
],
|
||||
|
||||
keys: ['birth_date', 'person.name', 'person.name', 'person.name', 'birth_date',],
|
||||
|
||||
parses: {
|
||||
birth_date: (rec: unknown): unknown => {
|
||||
const { person } = rec as Patient
|
||||
|
||||
if (typeof person.birthDate == 'object' && person.birthDate) {
|
||||
return (person.birthDate as Date).toLocaleDateString('id-ID')
|
||||
} else if (typeof person.birthDate == 'string') {
|
||||
return (person.birthDate as string).substring(0, 10)
|
||||
}
|
||||
return person.birthDate
|
||||
},
|
||||
},
|
||||
|
||||
components: {
|
||||
|
||||
},
|
||||
|
||||
htmls: {
|
||||
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
<script setup lang="ts">
|
||||
import Dialog from '~/components/pub/my-ui/modal/dialog.vue'
|
||||
import type { PaginationMeta } from '~/components/pub/my-ui/pagination/pagination.type'
|
||||
import PaginationView from '~/components/pub/my-ui/pagination/pagination-view.vue'
|
||||
import { config } from './national-program-list.cfg'
|
||||
import { cn } from '~/lib/utils'
|
||||
import { CalendarDate, DateFormatter, getLocalTimeZone } from '@internationalized/date'
|
||||
import type { DateRange } from 'radix-vue'
|
||||
import { CalendarIcon } from 'lucide-vue-next'
|
||||
import type { Item } from '~/components/pub/my-ui/combobox'
|
||||
import Select from '~/components/pub/my-ui/form/select.vue'
|
||||
import * as DE from '~/components/pub/my-ui/doc-entry'
|
||||
|
||||
interface Props {
|
||||
data: any[]
|
||||
paginationMeta: PaginationMeta
|
||||
searchValue: string
|
||||
statusValue: string
|
||||
}
|
||||
const props = defineProps<Props>()
|
||||
const isModalOpen = inject(`isNationalProgramServiceHistoryOpen`) as Ref<boolean>
|
||||
|
||||
const emit = defineEmits<{
|
||||
pageChange: [page: number]
|
||||
'update:searchValue': [value: string]
|
||||
'update:statusValue': [value: string]
|
||||
}>()
|
||||
|
||||
function handlePageChange(page: number) {
|
||||
emit('pageChange', page)
|
||||
}
|
||||
|
||||
const statusOptions: Item[] = [
|
||||
{ value: 'all', label: 'All Statuses' },
|
||||
{ value: 'pending', label: 'Pending' },
|
||||
{ value: 'active', label: 'Active' },
|
||||
{ value: 'completed', label: 'Completed' },
|
||||
{ value: 'archived', label: 'Archived' },
|
||||
]
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Dialog v-model:open="isModalOpen" title="" size="2xl">
|
||||
<div class="space-y-4">
|
||||
<DE.Block :col-count="4" class="" :cell-flex="false">
|
||||
<Input
|
||||
v-model="props.searchValue"
|
||||
class=""
|
||||
placeholder="Cari .."/>
|
||||
<Select
|
||||
:items="statusOptions"
|
||||
:model-value="props.statusValue"
|
||||
@update:model-value="(data) => emit('update:statusValue', data)"
|
||||
/>
|
||||
</DE.Block>
|
||||
|
||||
<PubMyUiDataTable
|
||||
v-bind="config"
|
||||
:rows="data"
|
||||
:skeleton-size="props.paginationMeta?.pageSize"
|
||||
/>
|
||||
<PaginationView :pagination-meta="props.paginationMeta" @page-change="handlePageChange" />
|
||||
</div>
|
||||
</Dialog>
|
||||
</template>
|
||||
@@ -0,0 +1,30 @@
|
||||
import type { Config } from '~/components/pub/my-ui/data-table'
|
||||
import type { Patient } from '~/models/patient'
|
||||
|
||||
export const config: Config = {
|
||||
cols: [{}, {}, {}, {}, {},],
|
||||
|
||||
headers: [
|
||||
[
|
||||
{ label: 'Nomor' },
|
||||
{ label: 'Layanan Program Nasional' },
|
||||
{ label: 'Status' },
|
||||
],
|
||||
],
|
||||
|
||||
keys: ['person.name', 'person.name', 'person.name',],
|
||||
|
||||
parses: {
|
||||
// birth_date: (rec: unknown): unknown => {
|
||||
|
||||
// },
|
||||
},
|
||||
|
||||
components: {
|
||||
|
||||
},
|
||||
|
||||
htmls: {
|
||||
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
<script setup lang="ts">
|
||||
import Dialog from '~/components/pub/my-ui/modal/dialog.vue'
|
||||
import type { PaginationMeta } from '~/components/pub/my-ui/pagination/pagination.type'
|
||||
import PaginationView from '~/components/pub/my-ui/pagination/pagination-view.vue'
|
||||
import { config } from './supporting-list.cfg'
|
||||
import { cn } from '~/lib/utils'
|
||||
import { CalendarDate, DateFormatter, getLocalTimeZone } from '@internationalized/date'
|
||||
import type { DateRange } from 'radix-vue'
|
||||
import { CalendarIcon } from 'lucide-vue-next'
|
||||
|
||||
interface Props {
|
||||
data: any[]
|
||||
paginationMeta: PaginationMeta
|
||||
dateValue: DateRange
|
||||
}
|
||||
const props = defineProps<Props>()
|
||||
const isModalOpen = inject(`isSupportingHistoryOpen`) as Ref<boolean>
|
||||
|
||||
const df = new DateFormatter('en-US', { dateStyle: 'medium',})
|
||||
|
||||
const emit = defineEmits<{
|
||||
pageChange: [page: number]
|
||||
'update:dateValue': [value: DateRange]
|
||||
}>()
|
||||
|
||||
function handlePageChange(page: number) {
|
||||
emit('pageChange', page)
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Dialog v-model:open="isModalOpen" title="" size="2xl">
|
||||
<div class="space-y-4">
|
||||
<Popover>
|
||||
<PopoverTrigger as-child>
|
||||
<Button variant="outline" :class="cn('mb-1 w-[280px] justify-start text-left font-normal',
|
||||
!props.dateValue && 'text-muted-foreground')">
|
||||
<CalendarIcon class="mr-2 h-4 w-4" />
|
||||
<template v-if="props.dateValue.start">
|
||||
<template v-if="props.dateValue.end">
|
||||
{{ df.format(props.dateValue.start.toDate(getLocalTimeZone())) }} -
|
||||
{{ df.format(props.dateValue.end.toDate(getLocalTimeZone())) }}
|
||||
</template>
|
||||
|
||||
<template v-else>
|
||||
{{ df.format(props.dateValue.start.toDate(getLocalTimeZone())) }}
|
||||
</template>
|
||||
</template>
|
||||
<template v-else> Pick a date </template>
|
||||
</Button>
|
||||
</PopoverTrigger>
|
||||
<PopoverContent class="w-auto p-0">
|
||||
<RangeCalendar v-model="props.dateValue" initial-focus :number-of-months="2"
|
||||
@update:model-value="(date) => emit('update:dateValue', date)" />
|
||||
</PopoverContent>
|
||||
</Popover>
|
||||
|
||||
<PubMyUiDataTable
|
||||
v-bind="config"
|
||||
:rows="data"
|
||||
:skeleton-size="props.paginationMeta?.pageSize"
|
||||
/>
|
||||
<PaginationView :pagination-meta="props.paginationMeta" @page-change="handlePageChange" />
|
||||
</div>
|
||||
</Dialog>
|
||||
</template>
|
||||
@@ -0,0 +1,39 @@
|
||||
import type { Config } from '~/components/pub/my-ui/data-table'
|
||||
import type { Patient } from '~/models/patient'
|
||||
|
||||
export const config: Config = {
|
||||
cols: [{}, {}, {}, {}, {},],
|
||||
|
||||
headers: [
|
||||
[
|
||||
{ label: 'Tanggal Order' },
|
||||
{ label: 'No Lab' },
|
||||
{ label: 'Nama Pemeriksaan' },
|
||||
{ label: 'Tanggal Pemeriksaan' },
|
||||
],
|
||||
],
|
||||
|
||||
keys: ['birth_date', 'person.name', 'person.name', 'birth_date',],
|
||||
|
||||
parses: {
|
||||
birth_date: (rec: unknown): unknown => {
|
||||
const { person } = rec as Patient
|
||||
|
||||
if (typeof person.birthDate == 'object' && person.birthDate) {
|
||||
return (person.birthDate as Date).toLocaleDateString('id-ID')
|
||||
} else if (typeof person.birthDate == 'string') {
|
||||
return (person.birthDate as string).substring(0, 10)
|
||||
}
|
||||
return person.birthDate
|
||||
},
|
||||
},
|
||||
|
||||
components: {
|
||||
},
|
||||
|
||||
htmls: {
|
||||
// patient_address(_rec) {
|
||||
// return '-'
|
||||
// },
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,101 @@
|
||||
import type { Config } from '~/components/pub/my-ui/data-table'
|
||||
import type { Patient } from '~/models/patient'
|
||||
import { defineAsyncComponent } from 'vue'
|
||||
import { educationCodes, genderCodes } from '~/lib/constants'
|
||||
import { calculateAge } from '~/lib/utils'
|
||||
|
||||
const action = defineAsyncComponent(() => import('~/components/pub/my-ui/data/dropdown-action-dvvp.vue'))
|
||||
const statusBadge = defineAsyncComponent(() => import('./_common/verify-badge.vue'))
|
||||
|
||||
export const config: Config = {
|
||||
cols: [{width: 140}, {}, {}, {width: 140}, {width: 10},],
|
||||
|
||||
headers: [
|
||||
[
|
||||
{ label: 'Tgl Simpan' },
|
||||
{ label: 'DPJP' },
|
||||
{ label: 'KSM' },
|
||||
{ label: 'Status' },
|
||||
{ label: 'Action' },
|
||||
],
|
||||
],
|
||||
|
||||
keys: ['birth_date', 'number', 'person.name', 'status', 'action'],
|
||||
|
||||
delKeyNames: [
|
||||
{ key: 'code', label: 'Kode' },
|
||||
{ key: 'name', label: 'Nama' },
|
||||
],
|
||||
|
||||
parses: {
|
||||
patientId: (rec: unknown): unknown => {
|
||||
const patient = rec as Patient
|
||||
return patient.number
|
||||
},
|
||||
identity_number: (rec: unknown): unknown => {
|
||||
const { person } = rec as Patient
|
||||
|
||||
if (person.nationality == 'WNA') {
|
||||
return person.passportNumber
|
||||
}
|
||||
|
||||
return person.residentIdentityNumber || '-'
|
||||
},
|
||||
birth_date: (rec: unknown): unknown => {
|
||||
const { person } = rec as Patient
|
||||
|
||||
if (typeof person.birthDate == 'object' && person.birthDate) {
|
||||
return (person.birthDate as Date).toLocaleDateString('id-ID')
|
||||
} else if (typeof person.birthDate == 'string') {
|
||||
return (person.birthDate as string).substring(0, 10)
|
||||
}
|
||||
return person.birthDate
|
||||
},
|
||||
patient_age: (rec: unknown): unknown => {
|
||||
const { person } = rec as Patient
|
||||
return calculateAge(person.birthDate)
|
||||
},
|
||||
gender: (rec: unknown): unknown => {
|
||||
const { person } = rec as Patient
|
||||
|
||||
if (typeof person.gender_code == 'number' && person.gender_code >= 0) {
|
||||
return person.gender_code
|
||||
} else if (typeof person.gender_code === 'string' && person.gender_code) {
|
||||
return genderCodes[person.gender_code] || '-'
|
||||
}
|
||||
return '-'
|
||||
},
|
||||
education: (rec: unknown): unknown => {
|
||||
const { person } = rec as Patient
|
||||
if (typeof person.education_code == 'number' && person.education_code >= 0) {
|
||||
return person.education_code
|
||||
} else if (typeof person.education_code === 'string' && person.education_code) {
|
||||
return educationCodes[person.education_code] || '-'
|
||||
}
|
||||
return '-'
|
||||
},
|
||||
},
|
||||
|
||||
components: {
|
||||
action(rec, idx) {
|
||||
return {
|
||||
idx,
|
||||
rec: rec as object,
|
||||
component: action,
|
||||
}
|
||||
},
|
||||
status(rec, idx) {
|
||||
return {
|
||||
idx,
|
||||
rec: rec as object,
|
||||
component: statusBadge,
|
||||
}
|
||||
},
|
||||
},
|
||||
|
||||
htmls: {
|
||||
patient_address(_rec) {
|
||||
return '-'
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
<script setup lang="ts">
|
||||
import type { PaginationMeta } from '~/components/pub/my-ui/pagination/pagination.type'
|
||||
import PaginationView from '~/components/pub/my-ui/pagination/pagination-view.vue'
|
||||
import { config } from './list.cfg'
|
||||
|
||||
interface Props {
|
||||
data: any[]
|
||||
paginationMeta: PaginationMeta
|
||||
}
|
||||
|
||||
defineProps<Props>()
|
||||
|
||||
const emit = defineEmits<{
|
||||
pageChange: [page: number]
|
||||
}>()
|
||||
|
||||
function handlePageChange(page: number) {
|
||||
emit('pageChange', page)
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="space-y-4">
|
||||
<PubMyUiDataTable
|
||||
v-bind="config"
|
||||
:rows="data"
|
||||
:skeleton-size="paginationMeta?.pageSize"
|
||||
/>
|
||||
<PaginationView :pagination-meta="paginationMeta" @page-change="handlePageChange" />
|
||||
</div>
|
||||
</template>
|
||||
@@ -0,0 +1,98 @@
|
||||
<script setup lang="ts">
|
||||
import type { FormErrors } from '~/types/error'
|
||||
import { toTypedSchema } from '@vee-validate/zod'
|
||||
import FieldGroup from '~/components/pub/my-ui/form/field-group.vue'
|
||||
import Field from '~/components/pub/my-ui/form/field.vue'
|
||||
import Label from '~/components/pub/my-ui/form/label.vue'
|
||||
import Select from '~/components/pub/my-ui/form/select.vue'
|
||||
import { Form } from '~/components/pub/ui/form'
|
||||
import InputBase from '~/components/pub/my-ui/form/input-base.vue'
|
||||
import type { InstallationFormData } from '~/schemas/installation.schema'
|
||||
import TextCaptcha from '~/components/pub/my-ui/form/text-captcha.vue'
|
||||
|
||||
|
||||
const props = defineProps<{
|
||||
schema: any
|
||||
errors?: FormErrors
|
||||
}>()
|
||||
|
||||
const emit = defineEmits<{
|
||||
submit: [values: InstallationFormData, resetForm: () => void]
|
||||
cancel: [resetForm: () => void]
|
||||
}>()
|
||||
|
||||
const formSchema = toTypedSchema(props.schema)
|
||||
const captchaRef = ref<InstanceType<typeof TextCaptcha> | null>(null)
|
||||
|
||||
// Form submission handler
|
||||
function onSubmitForm(values: any, { resetForm }: { resetForm: () => void }) {
|
||||
const formData: InstallationFormData = {
|
||||
name: values.name || '',
|
||||
code: values.code || '',
|
||||
}
|
||||
emit('submit', formData, resetForm)
|
||||
}
|
||||
|
||||
// Form cancel handler
|
||||
function onCancelForm({ resetForm }: { resetForm: () => void }) {
|
||||
emit('cancel', resetForm)
|
||||
}
|
||||
|
||||
const items = ref([
|
||||
{ label: 'Rujukan Internal', value: 'ri' },
|
||||
{ label: 'SEP Rujukan', value: 'sr' },
|
||||
])
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Form
|
||||
v-slot="{ handleSubmit, resetForm }"
|
||||
as=""
|
||||
keep-values
|
||||
:validation-schema="formSchema"
|
||||
>
|
||||
<form id="entry-form" @submit="handleSubmit($event, (values) => onSubmitForm(values, { resetForm }))">
|
||||
<div class="mb-5 border-b border-b-slate-300 pb-3 text-lg xl:text-xl">
|
||||
<div class="flex flex-col justify-between">
|
||||
|
||||
<InputBase
|
||||
field-name="name"
|
||||
label="Nama"
|
||||
placeholder="Masukkan Nama"
|
||||
:errors="errors"/>
|
||||
<InputBase
|
||||
field-name="email"
|
||||
label="Email"
|
||||
placeholder="Masukkan Email"
|
||||
:errors="errors"/>
|
||||
|
||||
<div class="mt-2">
|
||||
<Label class="" for="password">Password</Label>
|
||||
<Field class="" id="password" :errors="errors">
|
||||
<FormField v-slot="{ componentField }" name="password">
|
||||
<FormItem>
|
||||
<FormControl>
|
||||
<Input
|
||||
id="password"
|
||||
v-bind="componentField"
|
||||
type="password"
|
||||
class="w-full"
|
||||
/>
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
</FormField>
|
||||
</Field>
|
||||
</div>
|
||||
|
||||
<TextCaptcha
|
||||
ref="captchaRef"
|
||||
:length="5"
|
||||
:useSpacing="true"
|
||||
:noiseChars="true"/>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</Form>
|
||||
</template>
|
||||
Reference in New Issue
Block a user