Merge branch 'dev' into feat/device-order-58
This commit is contained in:
@@ -22,3 +22,5 @@ logs
|
||||
.env
|
||||
.env.*
|
||||
!.env.example
|
||||
|
||||
.vscode
|
||||
Vendored
-15
@@ -1,15 +0,0 @@
|
||||
{
|
||||
// Use IntelliSense to learn about possible attributes.
|
||||
// Hover to view descriptions of existing attributes.
|
||||
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
{
|
||||
"type": "chrome",
|
||||
"request": "launch",
|
||||
"name": "Launch Chrome against localhost",
|
||||
"url": "http://localhost:3000",
|
||||
"webRoot": "${workspaceFolder}"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -174,7 +174,7 @@ body {
|
||||
}
|
||||
|
||||
body, table, label {
|
||||
@apply md:!text-xs 2xl:!text-sm;
|
||||
@apply md:!text-xs 2xl:!text-sm;
|
||||
}
|
||||
|
||||
/* Container */
|
||||
|
||||
@@ -1,119 +1,114 @@
|
||||
import type {
|
||||
Col,
|
||||
KeyLabel,
|
||||
RecComponent,
|
||||
RecStrFuncComponent,
|
||||
RecStrFuncUnknown,
|
||||
Th,
|
||||
} from '~/components/pub/my-ui/data/types'
|
||||
import { defineAsyncComponent } from 'vue'
|
||||
import type { Config, RecComponent } from '~/components/pub/my-ui/data-table'
|
||||
|
||||
type SmallDetailDto = any
|
||||
|
||||
const action = defineAsyncComponent(() => import('~/components/pub/my-ui/data/dropdown-action-dud.vue'))
|
||||
|
||||
export const cols: Col[] = [
|
||||
{},
|
||||
{},
|
||||
{},
|
||||
{ width: 100 },
|
||||
{ width: 120 },
|
||||
{},
|
||||
{},
|
||||
{},
|
||||
{ width: 100 },
|
||||
{ width: 100 },
|
||||
{},
|
||||
{ width: 50 },
|
||||
]
|
||||
|
||||
export const header: Th[][] = [
|
||||
[
|
||||
{ label: 'Nama' },
|
||||
{ label: 'Rekam Medis' },
|
||||
{ label: 'KTP' },
|
||||
{ label: 'Tgl Lahir' },
|
||||
{ label: 'Umur' },
|
||||
{ label: 'JK' },
|
||||
{ label: 'Pendidikan' },
|
||||
{ label: 'Status' },
|
||||
{ label: '' },
|
||||
export const config: Config = {
|
||||
cols: [
|
||||
{},
|
||||
{},
|
||||
{},
|
||||
{ width: 100 },
|
||||
{ width: 120 },
|
||||
{},
|
||||
{},
|
||||
{},
|
||||
{ width: 100 },
|
||||
{ width: 100 },
|
||||
{},
|
||||
{ width: 50 },
|
||||
],
|
||||
]
|
||||
|
||||
export const keys = [
|
||||
'name',
|
||||
'medicalRecord_number',
|
||||
'identity_number',
|
||||
'birth_date',
|
||||
'patient_age',
|
||||
'gender',
|
||||
'education',
|
||||
'status',
|
||||
'action',
|
||||
]
|
||||
headers: [
|
||||
[
|
||||
{ label: 'Nama' },
|
||||
{ label: 'Rekam Medis' },
|
||||
{ label: 'KTP' },
|
||||
{ label: 'Tgl Lahir' },
|
||||
{ label: 'Umur' },
|
||||
{ label: 'JK' },
|
||||
{ label: 'Pendidikan' },
|
||||
{ label: 'Status' },
|
||||
{ label: '' },
|
||||
],
|
||||
],
|
||||
|
||||
export const delKeyNames: KeyLabel[] = [
|
||||
{ key: 'code', label: 'Kode' },
|
||||
{ key: 'name', label: 'Nama' },
|
||||
]
|
||||
keys: [
|
||||
'name',
|
||||
'medicalRecord_number',
|
||||
'identity_number',
|
||||
'birth_date',
|
||||
'patient_age',
|
||||
'gender',
|
||||
'education',
|
||||
'status',
|
||||
'action',
|
||||
],
|
||||
|
||||
export const funcParsed: RecStrFuncUnknown = {
|
||||
name: (rec: unknown): unknown => {
|
||||
const recX = rec as SmallDetailDto
|
||||
return `${recX.firstName} ${recX.middleName || ''} ${recX.lastName || ''}`
|
||||
},
|
||||
identity_number: (rec: unknown): unknown => {
|
||||
const recX = rec as SmallDetailDto
|
||||
if (recX.identity_number?.substring(0, 5) === 'BLANK') {
|
||||
return '(TANPA NIK)'
|
||||
}
|
||||
return recX.identity_number
|
||||
},
|
||||
birth_date: (rec: unknown): unknown => {
|
||||
const recX = rec as SmallDetailDto
|
||||
if (typeof recX.birth_date == 'object' && recX.birth_date) {
|
||||
return (recX.birth_date as Date).toLocaleDateString()
|
||||
} else if (typeof recX.birth_date == 'string') {
|
||||
return (recX.birth_date as string).substring(0, 10)
|
||||
}
|
||||
return recX.birth_date
|
||||
},
|
||||
patient_age: (rec: unknown): unknown => {
|
||||
const recX = rec as SmallDetailDto
|
||||
return recX.birth_date?.split('T')[0]
|
||||
},
|
||||
gender: (rec: unknown): unknown => {
|
||||
const recX = rec as SmallDetailDto
|
||||
if (typeof recX?.gender_code !== 'number' && recX?.gender_code !== '') {
|
||||
return 'Tidak Diketahui'
|
||||
}
|
||||
return recX.gender_code
|
||||
},
|
||||
education: (rec: unknown): unknown => {
|
||||
const recX = rec as SmallDetailDto
|
||||
if (typeof recX.education_code == 'number' && recX.education_code >= 0) {
|
||||
return recX.education_code
|
||||
} else if (typeof recX.education_code) {
|
||||
return recX.education_code
|
||||
}
|
||||
return '-'
|
||||
},
|
||||
}
|
||||
delKeyNames: [
|
||||
{ key: 'code', label: 'Kode' },
|
||||
{ key: 'name', label: 'Nama' },
|
||||
],
|
||||
|
||||
export const funcComponent: RecStrFuncComponent = {
|
||||
action(rec, idx) {
|
||||
const res: RecComponent = {
|
||||
idx,
|
||||
rec: rec as object,
|
||||
component: action,
|
||||
}
|
||||
return res
|
||||
parses: {
|
||||
name: (rec: unknown): unknown => {
|
||||
const recX = rec as SmallDetailDto
|
||||
return `${recX.firstName} ${recX.middleName || ''} ${recX.lastName || ''}`
|
||||
},
|
||||
identity_number: (rec: unknown): unknown => {
|
||||
const recX = rec as SmallDetailDto
|
||||
if (recX.identity_number?.substring(0, 5) === 'BLANK') {
|
||||
return '(TANPA NIK)'
|
||||
}
|
||||
return recX.identity_number
|
||||
},
|
||||
birth_date: (rec: unknown): unknown => {
|
||||
const recX = rec as SmallDetailDto
|
||||
if (typeof recX.birth_date == 'object' && recX.birth_date) {
|
||||
return (recX.birth_date as Date).toLocaleDateString()
|
||||
} else if (typeof recX.birth_date == 'string') {
|
||||
return (recX.birth_date as string).substring(0, 10)
|
||||
}
|
||||
return recX.birth_date
|
||||
},
|
||||
patient_age: (rec: unknown): unknown => {
|
||||
const recX = rec as SmallDetailDto
|
||||
return recX.birth_date?.split('T')[0]
|
||||
},
|
||||
gender: (rec: unknown): unknown => {
|
||||
const recX = rec as SmallDetailDto
|
||||
if (typeof recX?.gender_code !== 'number' && recX?.gender_code !== '') {
|
||||
return 'Tidak Diketahui'
|
||||
}
|
||||
return recX.gender_code
|
||||
},
|
||||
education: (rec: unknown): unknown => {
|
||||
const recX = rec as SmallDetailDto
|
||||
if (typeof recX.education_code == 'number' && recX.education_code >= 0) {
|
||||
return recX.education_code
|
||||
} else if (typeof recX.education_code) {
|
||||
return recX.education_code
|
||||
}
|
||||
return '-'
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
export const funcHtml: RecStrFuncUnknown = {
|
||||
patient_address(_rec) {
|
||||
return '-'
|
||||
components: {
|
||||
action(rec: unknown, idx: number) {
|
||||
const res: RecComponent = {
|
||||
idx,
|
||||
rec: rec as object,
|
||||
component: action,
|
||||
}
|
||||
return res
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
htmls: {
|
||||
patient_address(rec: unknown) {
|
||||
return '-'
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
<script setup lang="ts">
|
||||
import { cols, funcComponent, funcHtml, funcParsed, header, keys } from './list-cfg'
|
||||
import { config } from './list-cfg'
|
||||
|
||||
defineProps<{
|
||||
data: any[]
|
||||
@@ -7,13 +7,5 @@ defineProps<{
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<PubMyUiDataTable
|
||||
:rows="data"
|
||||
:cols="cols"
|
||||
:header="header"
|
||||
:keys="keys"
|
||||
:func-parsed="funcParsed"
|
||||
:func-html="funcHtml"
|
||||
:func-component="funcComponent"
|
||||
/>
|
||||
<PubMyUiDataTable v-bind="config" :rows="data" />
|
||||
</template>
|
||||
|
||||
@@ -1,44 +1,44 @@
|
||||
import type {
|
||||
Col,
|
||||
KeyLabel,
|
||||
RecComponent,
|
||||
RecStrFuncComponent,
|
||||
RecStrFuncUnknown,
|
||||
Th,
|
||||
} from '~/components/pub/my-ui/data/types'
|
||||
import type { Config, RecComponent } from '~/components/pub/my-ui/data-table'
|
||||
import { defineAsyncComponent } from 'vue'
|
||||
|
||||
type SmallDetailDto = any
|
||||
|
||||
const action = defineAsyncComponent(() => import('~/components/pub/my-ui/data/dropdown-action-dud.vue'))
|
||||
|
||||
export const cols: Col[] = [{}, {}, {}, { width: 50 }]
|
||||
export const config: Config = {
|
||||
cols: [{}, {}, {}, { width: 50 }],
|
||||
|
||||
export const header: Th[][] = [[{ label: 'Kode' }, { label: 'Nama' }, { label: 'Kamar' }, { label: '' }]]
|
||||
headers: [[
|
||||
{ label: 'Kode' },
|
||||
{ label: 'Nama' },
|
||||
{ label: 'Kamar' },
|
||||
{ label: '' },
|
||||
]],
|
||||
|
||||
export const keys = ['code', 'name', 'parent', 'action']
|
||||
keys: ['code', 'name', 'parent', 'action'],
|
||||
|
||||
export const delKeyNames: KeyLabel[] = [
|
||||
{ key: 'code', label: 'Kode' },
|
||||
{ key: 'name', label: 'Nama' },
|
||||
]
|
||||
delKeyNames: [
|
||||
{ key: 'code', label: 'Kode' },
|
||||
{ key: 'name', label: 'Nama' },
|
||||
],
|
||||
|
||||
export const funcParsed: RecStrFuncUnknown = {
|
||||
parent: (rec: unknown): unknown => {
|
||||
const recX = rec as SmallDetailDto
|
||||
return recX.parent?.name || '-'
|
||||
parses: {
|
||||
parent: (rec: unknown): unknown => {
|
||||
const recX = rec as SmallDetailDto
|
||||
return recX.parent?.name || '-'
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
export const funcComponent: RecStrFuncComponent = {
|
||||
action(rec, idx) {
|
||||
const res: RecComponent = {
|
||||
idx,
|
||||
rec: rec as object,
|
||||
component: action,
|
||||
}
|
||||
return res
|
||||
components: {
|
||||
action(rec, idx) {
|
||||
const res: RecComponent = {
|
||||
idx,
|
||||
rec: rec as object,
|
||||
component: action,
|
||||
}
|
||||
return res
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
export const funcHtml: RecStrFuncUnknown = {}
|
||||
htmls: {},
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@ import PaginationView from '~/components/pub/my-ui/pagination/pagination-view.vu
|
||||
import type { PaginationMeta } from '~/components/pub/my-ui/pagination/pagination.type'
|
||||
|
||||
// Configs
|
||||
import { cols, funcComponent, funcHtml, funcParsed, header, keys } from './list-cfg'
|
||||
import { config } from './list-cfg'
|
||||
|
||||
interface Props {
|
||||
data: any[]
|
||||
@@ -27,13 +27,8 @@ function handlePageChange(page: number) {
|
||||
<template>
|
||||
<div class="space-y-4">
|
||||
<PubMyUiDataTable
|
||||
v-bind="config"
|
||||
:rows="data"
|
||||
:cols="cols"
|
||||
:header="header"
|
||||
:keys="keys"
|
||||
:func-parsed="funcParsed"
|
||||
:func-html="funcHtml"
|
||||
:func-component="funcComponent"
|
||||
:skeleton-size="paginationMeta?.pageSize"
|
||||
/>
|
||||
<PaginationView :pagination-meta="paginationMeta" @page-change="handlePageChange" />
|
||||
|
||||
@@ -1,37 +1,36 @@
|
||||
import type {
|
||||
Col,
|
||||
KeyLabel,
|
||||
RecComponent,
|
||||
RecStrFuncComponent,
|
||||
RecStrFuncUnknown,
|
||||
Th,
|
||||
} from '~/components/pub/my-ui/data/types'
|
||||
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-dud.vue'))
|
||||
|
||||
export const cols: Col[] = [{}, {}, { width: 50 }]
|
||||
export const config: Config = {
|
||||
cols: [{}, {}, { width: 50 }],
|
||||
|
||||
export const header: Th[][] = [[{ label: 'Kode' }, { label: 'Nama' }, { label: '' }]]
|
||||
headers: [[
|
||||
{ label: 'Kode' },
|
||||
{ label: 'Nama' },
|
||||
{ label: '' },
|
||||
]],
|
||||
|
||||
export const keys = ['code', 'name', 'action']
|
||||
keys: ['code', 'name', 'action'],
|
||||
|
||||
export const delKeyNames: KeyLabel[] = [
|
||||
{ key: 'code', label: 'Kode' },
|
||||
{ key: 'name', label: 'Nama' },
|
||||
]
|
||||
delKeyNames: [
|
||||
{ key: 'code', label: 'Kode' },
|
||||
{ key: 'name', label: 'Nama' },
|
||||
],
|
||||
|
||||
export const funcParsed: RecStrFuncUnknown = {}
|
||||
parses: {},
|
||||
|
||||
export const funcComponent: RecStrFuncComponent = {
|
||||
action(rec, idx) {
|
||||
const res: RecComponent = {
|
||||
idx,
|
||||
rec: rec as object,
|
||||
component: action,
|
||||
}
|
||||
return res
|
||||
components: {
|
||||
action(rec, idx) {
|
||||
const res: RecComponent = {
|
||||
idx,
|
||||
rec: rec as object,
|
||||
component: action,
|
||||
}
|
||||
return res
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
export const funcHtml: RecStrFuncUnknown = {}
|
||||
htmls: {},
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@ import PaginationView from '~/components/pub/my-ui/pagination/pagination-view.vu
|
||||
import type { PaginationMeta } from '~/components/pub/my-ui/pagination/pagination.type'
|
||||
|
||||
// Configs
|
||||
import { cols, funcComponent, funcHtml, funcParsed, header, keys } from './list-cfg'
|
||||
import { config } from './list-cfg'
|
||||
|
||||
interface Props {
|
||||
data: any[]
|
||||
@@ -27,13 +27,8 @@ function handlePageChange(page: number) {
|
||||
<template>
|
||||
<div class="space-y-4">
|
||||
<PubMyUiDataTable
|
||||
v-bind="config"
|
||||
:rows="data"
|
||||
:cols="cols"
|
||||
:header="header"
|
||||
:keys="keys"
|
||||
:func-parsed="funcParsed"
|
||||
:func-html="funcHtml"
|
||||
:func-component="funcComponent"
|
||||
:skeleton-size="paginationMeta?.pageSize"
|
||||
/>
|
||||
<PaginationView :pagination-meta="paginationMeta" @page-change="handlePageChange" />
|
||||
|
||||
@@ -1,44 +1,44 @@
|
||||
import type {
|
||||
Col,
|
||||
KeyLabel,
|
||||
RecComponent,
|
||||
RecStrFuncComponent,
|
||||
RecStrFuncUnknown,
|
||||
Th,
|
||||
} from '~/components/pub/my-ui/data/types'
|
||||
import type { Config, RecComponent } from '~/components/pub/my-ui/data-table'
|
||||
import { defineAsyncComponent } from 'vue'
|
||||
|
||||
type SmallDetailDto = any
|
||||
|
||||
const action = defineAsyncComponent(() => import('~/components/pub/my-ui/data/dropdown-action-dud.vue'))
|
||||
|
||||
export const cols: Col[] = [{}, {}, {}, { width: 50 }]
|
||||
export const config: Config = {
|
||||
cols: [{}, {}, {}, { width: 50 }],
|
||||
|
||||
export const header: Th[][] = [[{ label: 'Kode' }, { label: 'Nama' }, { label: 'Lantai' }, { label: '' }]]
|
||||
headers: [[
|
||||
{ label: 'Kode' },
|
||||
{ label: 'Nama' },
|
||||
{ label: 'Lantai' },
|
||||
{ label: '' },
|
||||
]],
|
||||
|
||||
export const keys = ['code', 'name', 'parent', 'action']
|
||||
keys: ['code', 'name', 'parent', 'action'],
|
||||
|
||||
export const delKeyNames: KeyLabel[] = [
|
||||
{ key: 'code', label: 'Kode' },
|
||||
{ key: 'name', label: 'Nama' },
|
||||
]
|
||||
delKeyNames: [
|
||||
{ key: 'code', label: 'Kode' },
|
||||
{ key: 'name', label: 'Nama' },
|
||||
],
|
||||
|
||||
export const funcParsed: RecStrFuncUnknown = {
|
||||
parent: (rec: unknown): unknown => {
|
||||
const recX = rec as SmallDetailDto
|
||||
return recX.parent?.name || '-'
|
||||
parses: {
|
||||
parent: (rec: unknown): unknown => {
|
||||
const recX = rec as SmallDetailDto
|
||||
return recX.parent?.name || '-'
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
export const funcComponent: RecStrFuncComponent = {
|
||||
action(rec, idx) {
|
||||
const res: RecComponent = {
|
||||
idx,
|
||||
rec: rec as object,
|
||||
component: action,
|
||||
}
|
||||
return res
|
||||
components: {
|
||||
action(rec, idx) {
|
||||
const res: RecComponent = {
|
||||
idx,
|
||||
rec: rec as object,
|
||||
component: action,
|
||||
}
|
||||
return res
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
export const funcHtml: RecStrFuncUnknown = {}
|
||||
htmls: {},
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@ import PaginationView from '~/components/pub/my-ui/pagination/pagination-view.vu
|
||||
import type { PaginationMeta } from '~/components/pub/my-ui/pagination/pagination.type'
|
||||
|
||||
// Configs
|
||||
import { cols, funcComponent, funcHtml, funcParsed, header, keys } from './list-cfg'
|
||||
import { config } from './list-cfg'
|
||||
|
||||
interface Props {
|
||||
data: any[]
|
||||
@@ -27,13 +27,8 @@ function handlePageChange(page: number) {
|
||||
<template>
|
||||
<div class="space-y-4">
|
||||
<PubMyUiDataTable
|
||||
v-bind="config"
|
||||
:rows="data"
|
||||
:cols="cols"
|
||||
:header="header"
|
||||
:keys="keys"
|
||||
:func-parsed="funcParsed"
|
||||
:func-html="funcHtml"
|
||||
:func-component="funcComponent"
|
||||
:skeleton-size="paginationMeta?.pageSize"
|
||||
/>
|
||||
<PaginationView :pagination-meta="paginationMeta" @page-change="handlePageChange" />
|
||||
|
||||
@@ -0,0 +1,126 @@
|
||||
<script setup lang="ts">
|
||||
// Components
|
||||
import * as DE from '~/components/pub/my-ui/doc-entry'
|
||||
|
||||
// Types
|
||||
import type { ConsultationFormData } from '~/schemas/consultation.schema.ts'
|
||||
|
||||
// Helpers
|
||||
import type z from 'zod'
|
||||
import { toTypedSchema } from '@vee-validate/zod'
|
||||
import { useForm } from 'vee-validate'
|
||||
import Textarea from '~/components/pub/ui/textarea/Textarea.vue'
|
||||
import type { CreateDto } from '~/models/consultation'
|
||||
|
||||
interface Props {
|
||||
schema: z.ZodSchema<any>
|
||||
values: CreateDto
|
||||
encounter_id: number
|
||||
units: { value: string; label: string }[]
|
||||
isLoading?: boolean
|
||||
isReadonly?: boolean
|
||||
}
|
||||
|
||||
const props = defineProps<Props>()
|
||||
const isLoading = props.isLoading !== undefined ? props.isLoading : false
|
||||
const isReadonly = props.isReadonly !== undefined ? props.isReadonly : false
|
||||
const emit = defineEmits<{
|
||||
submit: [values: ConsultationFormData, resetForm: () => void]
|
||||
cancel: [resetForm: () => void]
|
||||
}>()
|
||||
|
||||
const today = new Date()
|
||||
const { defineField, errors, meta } = useForm({
|
||||
validationSchema: toTypedSchema(props.schema),
|
||||
initialValues: {
|
||||
date: props.values.date || today.toISOString().slice(0, 10),
|
||||
problem: '',
|
||||
dstUnit_id: 0,
|
||||
} as Partial<ConsultationFormData>,
|
||||
})
|
||||
|
||||
const [date, dateAttrs] = defineField('date')
|
||||
const [unit_id, unitAttrs] = defineField('unit_id')
|
||||
const [problem, problemAttrs] = defineField('problem')
|
||||
|
||||
// Fill fields from props.values if provided
|
||||
if (props.values) {
|
||||
if (props.values.date !== undefined) date.value = props.values.date.substring(0, 10)
|
||||
if (props.values.dstUnit_id !== undefined) unit_id.value = props.values.dstUnit_id
|
||||
if (props.values.problem !== undefined) problem.value = props.values.problem
|
||||
}
|
||||
|
||||
const resetForm = () => {
|
||||
date.value = date.value ?? today.toISOString().slice(0, 10)
|
||||
unit_id.value = 0
|
||||
problem.value = ''
|
||||
}
|
||||
|
||||
// Form submission handler
|
||||
function onSubmitForm(values: any) {
|
||||
const formData: ConsultationFormData = {
|
||||
encounter_id: props.encounter_id,
|
||||
date: date.value ? `${date.value}T00:00:00Z` : '',
|
||||
problem: problem.value || '',
|
||||
dstUnit_id: unit_id.value || 0,
|
||||
}
|
||||
emit('submit', formData, resetForm)
|
||||
}
|
||||
|
||||
// Form cancel handler
|
||||
function onCancelForm() {
|
||||
emit('cancel', resetForm)
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<form id="form-division" @submit.prevent>
|
||||
<DE.Block labelSize="thin" class="!mb-2.5 !pt-0 xl:!mb-3" :colCount="3" :cellFlex="false">
|
||||
<DE.Cell>
|
||||
<DE.Label>Tanggal</DE.Label>
|
||||
<DE.Field :errMessage="errors.code">
|
||||
<Input
|
||||
v-model.number="date"
|
||||
icon-name="i-lucide-chevron-down"
|
||||
v-bind="dateAttrs"
|
||||
readonly
|
||||
/>
|
||||
</DE.Field>
|
||||
</DE.Cell>
|
||||
<DE.Cell>
|
||||
<DE.Label>Unit</DE.Label>
|
||||
<DE.Field :errMessage="errors.unit_id">
|
||||
{{ errors.unit_id }}
|
||||
<Select
|
||||
id="strUnit_id"
|
||||
v-model.number="unit_id"
|
||||
icon-name="i-lucide-chevron-down"
|
||||
placeholder="Pilih kelompok obat"
|
||||
v-bind="unitAttrs"
|
||||
:items="props.units || []"
|
||||
:disabled="isLoading || isReadonly"
|
||||
/>
|
||||
<!-- <Input type="number" id="unit_id" v-model.number="unit_id" v-bind="unitAttrs" :disabled="isLoading || isReadonly" /> -->
|
||||
</DE.Field>
|
||||
</DE.Cell>
|
||||
<DE.Cell :colSpan="3">
|
||||
<DE.Label>Uraian</DE.Label>
|
||||
<DE.Field :errMessage="errors.problem">
|
||||
<Textarea id="problem" v-model="problem" v-bind="problemAttrs" :disabled="isLoading || isReadonly" />
|
||||
</DE.Field>
|
||||
</DE.Cell>
|
||||
</DE.Block>
|
||||
<div class="my-2 flex justify-end gap-2 py-2">
|
||||
<Button type="button" variant="secondary" class="w-[120px]" @click="onCancelForm"> Kembali </Button>
|
||||
<Button
|
||||
v-if="!isReadonly"
|
||||
type="button"
|
||||
class="w-[120px]"
|
||||
:disabled="isLoading || !meta.valid"
|
||||
@click="onSubmitForm"
|
||||
>
|
||||
Simpan
|
||||
</Button>
|
||||
</div>
|
||||
</form>
|
||||
</template>
|
||||
@@ -0,0 +1,54 @@
|
||||
import type { Config, RecComponent, RecStrFuncComponent, RecStrFuncUnknown } from '~/components/pub/my-ui/data-table'
|
||||
import { defineAsyncComponent } from 'vue'
|
||||
import type { Consultation } from '~/models/consultation'
|
||||
|
||||
type SmallDetailDto = any
|
||||
|
||||
const action = defineAsyncComponent(() => import('~/components/pub/my-ui/data/dropdown-action-ud.vue'))
|
||||
export const config: Config = {
|
||||
cols: [{ width: 100 }, {}, {}, {}, { width: 50 }],
|
||||
headers: [[
|
||||
{ label: 'Tanggal' },
|
||||
{ label: 'Tujuan' },
|
||||
{ label: 'Dokter' },
|
||||
{ label: 'Pertanyaan' },
|
||||
{ label: 'Jawaban' },
|
||||
{ label: '' },
|
||||
]],
|
||||
keys: ['date', 'dstUnit.name', 'dstDoctor.name', 'problem', 'solution', 'action'],
|
||||
delKeyNames: [
|
||||
{ key: 'data', label: 'Tanggal' },
|
||||
{ key: 'dstDoctor.name', label: 'Dokter' },
|
||||
],
|
||||
parses: {
|
||||
action(rec, idx) {
|
||||
const res: RecComponent = {
|
||||
idx,
|
||||
rec: rec as object,
|
||||
component: action,
|
||||
props: {
|
||||
size: 'sm',
|
||||
},
|
||||
}
|
||||
return res
|
||||
},
|
||||
date(rec) {
|
||||
const recX = rec as Consultation
|
||||
return recX.date?.substring(0, 10) || '-'
|
||||
}
|
||||
},
|
||||
components: {
|
||||
action(rec, idx) {
|
||||
const res: RecComponent = {
|
||||
idx,
|
||||
rec: rec as object,
|
||||
component: action,
|
||||
props: {
|
||||
size: 'sm',
|
||||
},
|
||||
}
|
||||
return res
|
||||
},
|
||||
} as RecStrFuncComponent,
|
||||
htmls: {} as RecStrFuncUnknown,
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
<script setup lang="ts">
|
||||
import type { PaginationMeta } from '~/components/pub/my-ui/pagination/pagination.type'
|
||||
import PaginationView from '~/components/pub/my-ui/pagination/pagination-view.vue'
|
||||
import { config } from './list.cfg'
|
||||
|
||||
interface Props {
|
||||
data: any[]
|
||||
paginationMeta: PaginationMeta
|
||||
}
|
||||
const props = defineProps<Props>()
|
||||
|
||||
const emit = defineEmits<{
|
||||
pageChange: [page: number]
|
||||
}>()
|
||||
|
||||
function handlePageChange(page: number) {
|
||||
emit('pageChange', page)
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="space-y-4">
|
||||
<PubMyUiDataTable
|
||||
v-bind="config"
|
||||
:rows="data"
|
||||
:skeleton-size="paginationMeta?.pageSize"
|
||||
/>
|
||||
<!-- FIXME: pindahkan ke content/division/list.vue -->
|
||||
<PaginationView :pagination-meta="paginationMeta" @page-change="handlePageChange" />
|
||||
</div>
|
||||
</template>
|
||||
@@ -1,37 +1,36 @@
|
||||
import type {
|
||||
Col,
|
||||
KeyLabel,
|
||||
RecComponent,
|
||||
RecStrFuncComponent,
|
||||
RecStrFuncUnknown,
|
||||
Th,
|
||||
} from '~/components/pub/my-ui/data/types'
|
||||
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-dud.vue'))
|
||||
|
||||
export const cols: Col[] = [{}, {}, { width: 50 }]
|
||||
export const config: Config = {
|
||||
cols: [{}, {}, { width: 50 }],
|
||||
|
||||
export const header: Th[][] = [[{ label: 'Kode' }, { label: 'Nama' }, { label: '' }]]
|
||||
headers: [[
|
||||
{ label: 'Kode' },
|
||||
{ label: 'Nama' },
|
||||
{ label: '' },
|
||||
]],
|
||||
|
||||
export const keys = ['code', 'name', 'action']
|
||||
keys: ['code', 'name', 'action'],
|
||||
|
||||
export const delKeyNames: KeyLabel[] = [
|
||||
{ key: 'code', label: 'Kode' },
|
||||
{ key: 'name', label: 'Nama' },
|
||||
]
|
||||
delKeyNames: [
|
||||
{ key: 'code', label: 'Kode' },
|
||||
{ key: 'name', label: 'Nama' },
|
||||
],
|
||||
|
||||
export const funcParsed: RecStrFuncUnknown = {}
|
||||
parses: {},
|
||||
|
||||
export const funcComponent: RecStrFuncComponent = {
|
||||
action(rec, idx) {
|
||||
const res: RecComponent = {
|
||||
idx,
|
||||
rec: rec as object,
|
||||
component: action,
|
||||
}
|
||||
return res
|
||||
components: {
|
||||
action(rec, idx) {
|
||||
const res: RecComponent = {
|
||||
idx,
|
||||
rec: rec as object,
|
||||
component: action,
|
||||
}
|
||||
return res
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
export const funcHtml: RecStrFuncUnknown = {}
|
||||
htmls: {},
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@ import PaginationView from '~/components/pub/my-ui/pagination/pagination-view.vu
|
||||
import type { PaginationMeta } from '~/components/pub/my-ui/pagination/pagination.type'
|
||||
|
||||
// Configs
|
||||
import { cols, funcComponent, funcHtml, funcParsed, header, keys } from './list-cfg'
|
||||
import { config } from './list-cfg'
|
||||
|
||||
interface Props {
|
||||
data: any[]
|
||||
@@ -27,13 +27,8 @@ function handlePageChange(page: number) {
|
||||
<template>
|
||||
<div class="space-y-4">
|
||||
<PubMyUiDataTable
|
||||
v-bind="config"
|
||||
:rows="data"
|
||||
:cols="cols"
|
||||
:header="header"
|
||||
:keys="keys"
|
||||
:func-parsed="funcParsed"
|
||||
:func-html="funcHtml"
|
||||
:func-component="funcComponent"
|
||||
:skeleton-size="paginationMeta?.pageSize"
|
||||
/>
|
||||
<PaginationView :pagination-meta="paginationMeta" @page-change="handlePageChange" />
|
||||
|
||||
@@ -0,0 +1,137 @@
|
||||
<script setup lang="ts">
|
||||
// Components
|
||||
import Block from '~/components/pub/my-ui/doc-entry/block.vue'
|
||||
import Cell from '~/components/pub/my-ui/doc-entry/cell.vue'
|
||||
import Field from '~/components/pub/my-ui/doc-entry/field.vue'
|
||||
import Label from '~/components/pub/my-ui/doc-entry/label.vue'
|
||||
import Button from '~/components/pub/ui/button/Button.vue'
|
||||
|
||||
// Constants
|
||||
|
||||
// Types
|
||||
import type { DiagnoseSrcFormData } from '~/schemas/diagnose-src.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: DiagnoseSrcFormData, resetForm: () => void]
|
||||
cancel: [resetForm: () => void]
|
||||
}>()
|
||||
|
||||
const { defineField, errors, meta } = useForm({
|
||||
validationSchema: toTypedSchema(props.schema),
|
||||
initialValues: {
|
||||
code: '',
|
||||
name: '',
|
||||
parent_id: null,
|
||||
} as Partial<DiagnoseSrcFormData>,
|
||||
})
|
||||
|
||||
const [code, codeAttrs] = defineField('code')
|
||||
const [name, nameAttrs] = defineField('name')
|
||||
const [indName, indNameAttrs] = defineField('indName')
|
||||
|
||||
if (props.values) {
|
||||
if (props.values.code !== undefined) code.value = props.values.code
|
||||
if (props.values.name !== undefined) name.value = props.values.name
|
||||
if (props.values.indName !== undefined) indName.value = props.values.indName
|
||||
}
|
||||
|
||||
const resetForm = () => {
|
||||
code.value = ''
|
||||
name.value = ''
|
||||
indName.value = null
|
||||
}
|
||||
|
||||
function onSubmitForm() {
|
||||
const formData: DiagnoseSrcFormData = {
|
||||
code: code.value || '',
|
||||
name: name.value || '',
|
||||
indName: indName.value || null,
|
||||
}
|
||||
emit('submit', formData, resetForm)
|
||||
}
|
||||
|
||||
function onCancelForm() {
|
||||
emit('cancel', resetForm)
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<form
|
||||
id="form-diagnose-src"
|
||||
@submit.prevent
|
||||
>
|
||||
<Block
|
||||
labelSize="thin"
|
||||
class="!mb-2.5 !pt-0 xl:!mb-3"
|
||||
:colCount="1"
|
||||
>
|
||||
<Cell>
|
||||
<Label height="compact">Kode</Label>
|
||||
<Field :errMessage="errors.code">
|
||||
<Input
|
||||
id="code"
|
||||
v-model="code"
|
||||
v-bind="codeAttrs"
|
||||
:disabled="isLoading || isReadonly"
|
||||
/>
|
||||
</Field>
|
||||
</Cell>
|
||||
<Cell>
|
||||
<Label height="compact">Nama (FHIR)</Label>
|
||||
<Field :errMessage="errors.name">
|
||||
<Input
|
||||
id="name"
|
||||
v-model="name"
|
||||
v-bind="nameAttrs"
|
||||
:disabled="isLoading || isReadonly"
|
||||
/>
|
||||
</Field>
|
||||
</Cell>
|
||||
<Cell>
|
||||
<Label height="compact">Nama (ID)</Label>
|
||||
<Field :errMessage="errors.indName">
|
||||
<Input
|
||||
id="indName"
|
||||
v-model="indName"
|
||||
v-bind="indNameAttrs"
|
||||
: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,33 @@
|
||||
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-dud.vue'))
|
||||
|
||||
export const config: Config = {
|
||||
cols: [{}, {}, {}, { width: 50 }],
|
||||
|
||||
headers: [[{ label: 'Kode' }, { label: 'Nama (FHIR)' }, { label: 'Nama (ID)' }, { label: '' }]],
|
||||
|
||||
keys: ['code', 'name', 'indName', 'action'],
|
||||
|
||||
delKeyNames: [
|
||||
{ key: 'code', label: 'Kode' },
|
||||
{ key: 'name', label: 'Nama (FHIR)' },
|
||||
{ key: 'indName', label: 'Nama (ID)' },
|
||||
],
|
||||
|
||||
parses: {},
|
||||
|
||||
components: {
|
||||
action(rec, idx) {
|
||||
const res: RecComponent = {
|
||||
idx,
|
||||
rec: rec as object,
|
||||
component: action,
|
||||
}
|
||||
return res
|
||||
},
|
||||
},
|
||||
|
||||
htmls: {},
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
<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"
|
||||
:skeleton-size="paginationMeta?.pageSize"
|
||||
/>
|
||||
<PaginationView :pagination-meta="paginationMeta" @page-change="handlePageChange" />
|
||||
</div>
|
||||
</template>
|
||||
@@ -1,64 +1,59 @@
|
||||
import type {
|
||||
Col,
|
||||
KeyLabel,
|
||||
RecComponent,
|
||||
RecStrFuncComponent,
|
||||
RecStrFuncUnknown,
|
||||
Th,
|
||||
} from '~/components/pub/my-ui/data/types'
|
||||
import type { Config, RecComponent } from '~/components/pub/my-ui/data-table'
|
||||
import { defineAsyncComponent } from 'vue'
|
||||
|
||||
type SmallDetailDto = any
|
||||
|
||||
const action = defineAsyncComponent(() => import('~/components/pub/my-ui/data/dropdown-action-ud.vue'))
|
||||
|
||||
export const cols: Col[] = [{}, {}, {}, {}, {}, { width: 50 }]
|
||||
export const config: Config = {
|
||||
cols: [{}, {}, {}, {}, {}, { width: 50 }],
|
||||
|
||||
export const header: Th[][] = [
|
||||
[
|
||||
{ label: 'Kode' },
|
||||
{ label: 'Nama' },
|
||||
{ label: 'Divisi Induk' },
|
||||
{ label: 'Karyawan' },
|
||||
{ label: 'Status Kepala' },
|
||||
{ label: '' },
|
||||
headers: [
|
||||
[
|
||||
{ label: 'Kode' },
|
||||
{ label: 'Nama' },
|
||||
{ label: 'Divisi Induk' },
|
||||
{ label: 'Karyawan' },
|
||||
{ label: 'Status Kepala' },
|
||||
{ label: '' },
|
||||
],
|
||||
],
|
||||
]
|
||||
|
||||
export const keys = ['code', 'name', 'division', 'employee', 'head', 'action']
|
||||
keys: ['code', 'name', 'division', 'employee', 'head', 'action'],
|
||||
|
||||
export const delKeyNames: KeyLabel[] = [
|
||||
{ key: 'code', label: 'Kode' },
|
||||
{ key: 'name', label: 'Nama' },
|
||||
]
|
||||
delKeyNames: [
|
||||
{ key: 'code', label: 'Kode' },
|
||||
{ key: 'name', label: 'Nama' },
|
||||
],
|
||||
|
||||
export const funcParsed: RecStrFuncUnknown = {
|
||||
division: (rec: unknown): unknown => {
|
||||
const recX = rec as SmallDetailDto
|
||||
return recX.division?.name || '-'
|
||||
parses: {
|
||||
division: (rec: unknown): unknown => {
|
||||
const recX = rec as SmallDetailDto
|
||||
return recX.division?.name || '-'
|
||||
},
|
||||
employee: (rec: unknown): unknown => {
|
||||
const recX = rec as SmallDetailDto
|
||||
return recX.employee?.name || '-'
|
||||
},
|
||||
head: (rec: unknown): unknown => {
|
||||
const recX = rec as SmallDetailDto
|
||||
return recX.headStatus ? 'Ya' : 'Tidak'
|
||||
},
|
||||
},
|
||||
employee: (rec: unknown): unknown => {
|
||||
const recX = rec as SmallDetailDto
|
||||
return recX.employee?.name || '-'
|
||||
},
|
||||
head: (rec: unknown): unknown => {
|
||||
const recX = rec as SmallDetailDto
|
||||
return recX.headStatus ? 'Ya' : 'Tidak'
|
||||
|
||||
components: {
|
||||
action(rec, idx) {
|
||||
const res: RecComponent = {
|
||||
idx,
|
||||
rec: rec as object,
|
||||
component: action,
|
||||
props: {
|
||||
size: 'sm',
|
||||
},
|
||||
}
|
||||
return res
|
||||
},
|
||||
},
|
||||
|
||||
htmls: {},
|
||||
}
|
||||
|
||||
export const funcComponent: RecStrFuncComponent = {
|
||||
action(rec, idx) {
|
||||
const res: RecComponent = {
|
||||
idx,
|
||||
rec: rec as object,
|
||||
component: action,
|
||||
props: {
|
||||
size: 'sm',
|
||||
},
|
||||
}
|
||||
return res
|
||||
},
|
||||
}
|
||||
|
||||
export const funcHtml: RecStrFuncUnknown = {}
|
||||
|
||||
@@ -6,7 +6,7 @@ import PaginationView from '~/components/pub/my-ui/pagination/pagination-view.vu
|
||||
import type { PaginationMeta } from '~/components/pub/my-ui/pagination/pagination.type'
|
||||
|
||||
// Configs
|
||||
import { cols, funcComponent, funcHtml, funcParsed, header, keys } from './list-cfg'
|
||||
import { config } from './list-cfg'
|
||||
|
||||
interface Props {
|
||||
data: any[]
|
||||
@@ -27,13 +27,8 @@ function handlePageChange(page: number) {
|
||||
<template>
|
||||
<div class="space-y-4">
|
||||
<PubMyUiDataTable
|
||||
v-bind="config"
|
||||
:rows="data"
|
||||
:cols="cols"
|
||||
:header="header"
|
||||
:keys="keys"
|
||||
:func-parsed="funcParsed"
|
||||
:func-html="funcHtml"
|
||||
:func-component="funcComponent"
|
||||
:skeleton-size="paginationMeta?.pageSize"
|
||||
/>
|
||||
<PaginationView :pagination-meta="paginationMeta" @page-change="handlePageChange" />
|
||||
|
||||
@@ -0,0 +1,145 @@
|
||||
<script setup lang="ts">
|
||||
import type { TreeItem } from '~/components/pub/my-ui/select-tree/type'
|
||||
import type { FormErrors } from '~/types/error'
|
||||
import { toTypedSchema } from '@vee-validate/zod'
|
||||
import TreeSelect from '~/components/pub/my-ui/select-tree/tree-select.vue'
|
||||
import Combobox from '~/components/pub/my-ui/form/combobox.vue'
|
||||
import FieldGroup from '~/components/pub/my-ui/form/field-group.vue'
|
||||
import Field from '~/components/pub/my-ui/form/field.vue'
|
||||
import Label from '~/components/pub/my-ui/form/label.vue'
|
||||
import { Form } from '~/components/pub/ui/form'
|
||||
|
||||
interface DivisionFormData {
|
||||
name: string
|
||||
code: string
|
||||
parentId: string
|
||||
}
|
||||
const props = defineProps<{
|
||||
division: {
|
||||
msg: {
|
||||
placeholder: string
|
||||
search: string
|
||||
empty: string
|
||||
}
|
||||
items: {
|
||||
value: string
|
||||
label: string
|
||||
}[]
|
||||
}
|
||||
divisionTree?: {
|
||||
msg: {
|
||||
placeholder: string
|
||||
search: string
|
||||
empty: string
|
||||
}
|
||||
data: TreeItem[]
|
||||
onFetchChildren: (parentId: string) => Promise<void>
|
||||
}
|
||||
schema: any
|
||||
initialValues?: Partial<DivisionFormData>
|
||||
errors?: FormErrors
|
||||
}>()
|
||||
|
||||
const emit = defineEmits<{
|
||||
'submit': [values: DivisionFormData, resetForm: () => void]
|
||||
'cancel': [resetForm: () => void]
|
||||
}>()
|
||||
|
||||
const formSchema = toTypedSchema(props.schema)
|
||||
|
||||
// Form submission handler
|
||||
function onSubmitForm(values: any, { resetForm }: { resetForm: () => void }) {
|
||||
const formData: DivisionFormData = {
|
||||
name: values.name || '',
|
||||
code: values.code || '',
|
||||
parentId: values.parentId || '',
|
||||
}
|
||||
emit('submit', formData, resetForm)
|
||||
}
|
||||
|
||||
// Form cancel handler
|
||||
function onCancelForm({ resetForm }: { resetForm: () => void }) {
|
||||
emit('cancel', resetForm)
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Form
|
||||
v-slot="{ handleSubmit, resetForm }" as="" keep-values :validation-schema="formSchema"
|
||||
:initial-values="initialValues"
|
||||
>
|
||||
<form id="entry-form" @submit="handleSubmit($event, (values) => onSubmitForm(values, { resetForm }))">
|
||||
<div class="mb-5 border-b border-b-slate-300 pb-3 text-lg xl:text-xl">
|
||||
<div class="flex flex-col justify-between">
|
||||
<FieldGroup>
|
||||
<Label label-for="name">Nama</Label>
|
||||
<Field id="name" :errors="errors">
|
||||
<FormField v-slot="{ componentField }" name="name">
|
||||
<FormItem>
|
||||
<FormControl>
|
||||
<Input
|
||||
id="name" type="text" placeholder="Masukkan nama divisi" autocomplete="off"
|
||||
v-bind="componentField"
|
||||
/>
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
</FormField>
|
||||
</Field>
|
||||
</FieldGroup>
|
||||
|
||||
<FieldGroup>
|
||||
<Label label-for="code">Kode</Label>
|
||||
<Field id="code" :errors="errors">
|
||||
<FormField v-slot="{ componentField }" name="code">
|
||||
<FormItem>
|
||||
<FormControl>
|
||||
<Input id="code" type="text" placeholder="Masukkan kode divisi" autocomplete="off" v-bind="componentField" />
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
</FormField>
|
||||
</Field>
|
||||
</FieldGroup>
|
||||
|
||||
<FieldGroup>
|
||||
<Label label-for="parentId">Divisi Induk</Label>
|
||||
<Field id="parentId" :errors="errors">
|
||||
<FormField v-slot="{ componentField }" name="parentId">
|
||||
<FormItem>
|
||||
<FormControl>
|
||||
<!-- Gunakan TreeSelect jika divisionTree tersedia, fallback ke Combobox -->
|
||||
<TreeSelect
|
||||
v-if="props.divisionTree"
|
||||
id="parentId"
|
||||
:model-value="componentField.modelValue"
|
||||
:data="props.divisionTree.data"
|
||||
:on-fetch-children="props.divisionTree.onFetchChildren"
|
||||
@update:model-value="componentField.onChange"
|
||||
/>
|
||||
<Combobox
|
||||
v-else
|
||||
id="parentId" v-bind="componentField" :items="props.division.items"
|
||||
:placeholder="props.division.msg.placeholder" :search-placeholder="props.division.msg.search"
|
||||
:empty-message="props.division.msg.empty"
|
||||
/>
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
</FormField>
|
||||
</Field>
|
||||
</FieldGroup>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="flex justify-end gap-2 mt-4">
|
||||
<Button type="button" variant="outline" @click="onCancelForm({ resetForm })">
|
||||
Batal
|
||||
</Button>
|
||||
<Button type="submit">
|
||||
Simpan
|
||||
</Button>
|
||||
</div>
|
||||
</form>
|
||||
</Form>
|
||||
</template>
|
||||
@@ -1,47 +1,47 @@
|
||||
import type {
|
||||
Col,
|
||||
KeyLabel,
|
||||
RecComponent,
|
||||
RecStrFuncComponent,
|
||||
RecStrFuncUnknown,
|
||||
Th,
|
||||
} from '~/components/pub/my-ui/data/types'
|
||||
import type { Config, RecComponent } from '~/components/pub/my-ui/data-table'
|
||||
import { defineAsyncComponent } from 'vue'
|
||||
|
||||
type SmallDetailDto = any
|
||||
|
||||
const action = defineAsyncComponent(() => import('~/components/pub/my-ui/data/dropdown-action-ud.vue'))
|
||||
|
||||
export const cols: Col[] = [{}, {}, {}, { width: 50 }]
|
||||
export const config: Config = {
|
||||
cols: [{}, {}, {}, { width: 50 }],
|
||||
|
||||
export const header: Th[][] = [[{ label: 'Kode' }, { label: 'Nama' }, { label: 'Divisi Induk' }, { label: '' }]]
|
||||
headers: [[
|
||||
{ label: 'Kode' },
|
||||
{ label: 'Nama' },
|
||||
{ label: 'Divisi Induk' },
|
||||
{ label: '' },
|
||||
]],
|
||||
|
||||
export const keys = ['code', 'name', 'parent', 'action']
|
||||
keys: ['code', 'name', 'parent', 'action'],
|
||||
|
||||
export const delKeyNames: KeyLabel[] = [
|
||||
{ key: 'code', label: 'Kode' },
|
||||
{ key: 'name', label: 'Nama' },
|
||||
]
|
||||
delKeyNames: [
|
||||
{ key: 'code', label: 'Kode' },
|
||||
{ key: 'name', label: 'Nama' },
|
||||
],
|
||||
|
||||
export const funcParsed: RecStrFuncUnknown = {
|
||||
parent: (rec: unknown): unknown => {
|
||||
const recX = rec as SmallDetailDto
|
||||
return recX.parent?.name || '-'
|
||||
parses: {
|
||||
parent: (rec: unknown): unknown => {
|
||||
const recX = rec as SmallDetailDto
|
||||
return recX.parent?.name || '-'
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
export const funcComponent: RecStrFuncComponent = {
|
||||
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
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
export const funcHtml: RecStrFuncUnknown = {}
|
||||
htmls: {},
|
||||
}
|
||||
@@ -6,7 +6,7 @@ import PaginationView from '~/components/pub/my-ui/pagination/pagination-view.vu
|
||||
import type { PaginationMeta } from '~/components/pub/my-ui/pagination/pagination.type'
|
||||
|
||||
// Configs
|
||||
import { cols, funcComponent, funcHtml, funcParsed, header, keys } from './list-cfg'
|
||||
import { config } from './list-cfg'
|
||||
|
||||
interface Props {
|
||||
data: any[]
|
||||
@@ -27,13 +27,8 @@ function handlePageChange(page: number) {
|
||||
<template>
|
||||
<div class="space-y-4">
|
||||
<PubMyUiDataTable
|
||||
v-bind="config"
|
||||
:rows="data"
|
||||
:cols="cols"
|
||||
:header="header"
|
||||
:keys="keys"
|
||||
:func-parsed="funcParsed"
|
||||
:func-html="funcHtml"
|
||||
:func-component="funcComponent"
|
||||
:skeleton-size="paginationMeta?.pageSize"
|
||||
/>
|
||||
<PaginationView :pagination-meta="paginationMeta" @page-change="handlePageChange" />
|
||||
|
||||
@@ -0,0 +1,165 @@
|
||||
<script setup lang="ts">
|
||||
import TreeSelect from '~/components/pub/my-ui/select-tree/tree-select.vue'
|
||||
|
||||
/**
|
||||
* DEMO COMPONENT - Tree Select dengan Lazy Loading
|
||||
*
|
||||
* Komponen ini adalah contoh penggunaan TreeSelect dengan data teknologi.
|
||||
* Untuk penggunaan dalam aplikasi nyata, lihat komponen content/division/entry.vue
|
||||
* yang menggunakan tree select untuk data divisi rumah sakit.
|
||||
*/
|
||||
|
||||
// Tipe data untuk konsistensi
|
||||
interface TreeItem {
|
||||
value: string
|
||||
label: string
|
||||
hasChildren: boolean
|
||||
children?: TreeItem[]
|
||||
}
|
||||
|
||||
// State untuk data pohon demo - data teknologi sebagai contoh
|
||||
const treeData = ref<TreeItem[]>([
|
||||
{ value: 'frontend', label: 'Frontend Development', hasChildren: true },
|
||||
{ value: 'backend', label: 'Backend Development', hasChildren: true },
|
||||
{ value: 'mobile', label: 'Mobile Development', hasChildren: true },
|
||||
{ value: 'devops', label: 'DevOps & Infrastructure', hasChildren: false },
|
||||
])
|
||||
|
||||
// State untuk menampung nilai yang dipilih
|
||||
const selectedValue = ref<string>()
|
||||
|
||||
// --- DEMO LOGIC: SIMULASI API DAN MANIPULASI DATA ---
|
||||
|
||||
// Helper: Fungsi rekursif untuk mencari dan menyisipkan data anak ke dalam state
|
||||
function findAndInsertChildren(nodes: TreeItem[], parentId: string, newChildren: TreeItem[]): boolean {
|
||||
for (let i = 0; i < nodes.length; i++) {
|
||||
const node = nodes[i]
|
||||
if (node && node.value === parentId) {
|
||||
// Gunakan Vue.set equivalent untuk memastikan reactivity
|
||||
node.children = [...newChildren]
|
||||
console.log(`[findAndInsertChildren] Updated children for ${parentId}:`, node.children)
|
||||
return true
|
||||
}
|
||||
if (node && node.children && findAndInsertChildren(node.children, parentId, newChildren)) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// Fungsi demo untuk simulasi fetch data dari API
|
||||
async function handleFetchChildren(parentId: string): Promise<void> {
|
||||
console.log(`[DEMO] Mengambil data anak untuk parent: ${parentId}`)
|
||||
|
||||
// Simulasi delay API call
|
||||
await new Promise(resolve => setTimeout(resolve, 600))
|
||||
|
||||
let childrenData: TreeItem[] = []
|
||||
|
||||
// Sample data berdasarkan parent ID
|
||||
switch (parentId) {
|
||||
case 'frontend':
|
||||
childrenData = [
|
||||
{ value: 'vue', label: 'Vue.js', hasChildren: true },
|
||||
{ value: 'react', label: 'React.js', hasChildren: true },
|
||||
{ value: 'angular', label: 'Angular', hasChildren: false },
|
||||
{ value: 'svelte', label: 'Svelte', hasChildren: false },
|
||||
]
|
||||
break
|
||||
case 'backend':
|
||||
childrenData = [
|
||||
{ value: 'nodejs', label: 'Node.js', hasChildren: true },
|
||||
{ value: 'python', label: 'Python', hasChildren: true },
|
||||
{ value: 'golang', label: 'Go', hasChildren: false },
|
||||
{ value: 'rust', label: 'Rust', hasChildren: false },
|
||||
]
|
||||
break
|
||||
case 'mobile':
|
||||
childrenData = [
|
||||
{ value: 'flutter', label: 'Flutter', hasChildren: false },
|
||||
{ value: 'react-native', label: 'React Native', hasChildren: false },
|
||||
{ value: 'ionic', label: 'Ionic', hasChildren: false },
|
||||
]
|
||||
break
|
||||
case 'vue':
|
||||
childrenData = [
|
||||
{ value: 'nuxt', label: 'Nuxt.js', hasChildren: false },
|
||||
{ value: 'quasar', label: 'Quasar', hasChildren: false },
|
||||
]
|
||||
break
|
||||
case 'react':
|
||||
childrenData = [
|
||||
{ value: 'nextjs', label: 'Next.js', hasChildren: false },
|
||||
{ value: 'gatsby', label: 'Gatsby', hasChildren: false },
|
||||
]
|
||||
break
|
||||
case 'nodejs':
|
||||
childrenData = [
|
||||
{ value: 'express', label: 'Express.js', hasChildren: false },
|
||||
{ value: 'nestjs', label: 'NestJS', hasChildren: false },
|
||||
{ value: 'fastify', label: 'Fastify', hasChildren: false },
|
||||
]
|
||||
break
|
||||
case 'python':
|
||||
childrenData = [
|
||||
{ value: 'django', label: 'Django', hasChildren: false },
|
||||
{ value: 'fastapi', label: 'FastAPI', hasChildren: false },
|
||||
{ value: 'flask', label: 'Flask', hasChildren: false },
|
||||
]
|
||||
break
|
||||
}
|
||||
|
||||
// Insert data ke dalam tree state
|
||||
const success = findAndInsertChildren(treeData.value, parentId, childrenData)
|
||||
console.log(`[DEMO] Insert children result:`, success)
|
||||
|
||||
// Force trigger reactivity
|
||||
triggerRef(treeData)
|
||||
console.log(`[DEMO] Current tree data:`, JSON.stringify(treeData.value, null, 2))
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="p-10 max-w-2xl mx-auto">
|
||||
<div class="mb-6">
|
||||
<h1 class="mb-2 text-3xl font-bold text-slate-800">Demo: Tree Select dengan Lazy Loading</h1>
|
||||
<p class="text-slate-600">
|
||||
Contoh penggunaan komponen TreeSelect dengan data teknologi.
|
||||
Pilih item untuk melihat sub-kategori yang dimuat secara lazy.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="mb-6 p-4 bg-blue-50 border border-blue-200 rounded-lg">
|
||||
<h3 class="font-semibold text-blue-800 mb-2">💡 Catatan untuk Developer:</h3>
|
||||
<p class="text-sm text-blue-700">
|
||||
Untuk implementasi nyata dengan data divisi rumah sakit,
|
||||
lihat komponen <code class="px-1 bg-blue-100 rounded">content/division/entry.vue</code>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="space-y-4">
|
||||
<div>
|
||||
<label class="block text-sm font-medium text-slate-700 mb-2">
|
||||
Pilih Teknologi:
|
||||
</label>
|
||||
<TreeSelect
|
||||
v-model="selectedValue"
|
||||
:data="treeData"
|
||||
:on-fetch-children="handleFetchChildren"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="p-4 bg-slate-50 rounded-lg">
|
||||
<p class="text-sm text-slate-600 mb-1">Value yang terpilih:</p>
|
||||
<span class="px-3 py-1 font-mono text-sm bg-white border rounded-md">
|
||||
{{ selectedValue || 'Belum ada yang dipilih' }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mt-8 text-xs text-slate-500">
|
||||
<p>🔄 Data dimuat secara lazy saat node parent dibuka</p>
|
||||
<p>⏱️ Simulasi delay 600ms untuk menampilkan loading state</p>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
@@ -1,11 +1,4 @@
|
||||
import type {
|
||||
Col,
|
||||
KeyLabel,
|
||||
RecComponent,
|
||||
RecStrFuncComponent,
|
||||
RecStrFuncUnknown,
|
||||
Th,
|
||||
} from '~/components/pub/my-ui/data/types'
|
||||
import type { Config, RecComponent } from '~/components/pub/my-ui/data-table'
|
||||
import { defineAsyncComponent } from 'vue'
|
||||
|
||||
type SmallDetailDto = any
|
||||
@@ -18,97 +11,99 @@ const _doctorStatus = {
|
||||
1: 'Aktif',
|
||||
}
|
||||
|
||||
export const cols: Col[] = [
|
||||
{ width: 100 },
|
||||
{ width: 250 },
|
||||
{},
|
||||
{ width: 100 },
|
||||
{ width: 100 },
|
||||
{},
|
||||
{},
|
||||
{},
|
||||
{ width: 120 },
|
||||
{ width: 100 },
|
||||
{},
|
||||
{},
|
||||
]
|
||||
|
||||
export const header: Th[][] = [
|
||||
[
|
||||
{ label: 'Kode JKN' },
|
||||
{ label: 'Nama' },
|
||||
{ label: 'No KTP' },
|
||||
{ label: 'No SIP' },
|
||||
{ label: 'No IHS' },
|
||||
{ label: 'Telpon' },
|
||||
{ label: 'Fee Ranap' },
|
||||
{ label: 'Fee Rajal' },
|
||||
{ label: 'Status' },
|
||||
{ label: '' },
|
||||
export const config: Config = {
|
||||
cols: [
|
||||
{ width: 100 },
|
||||
{ width: 250 },
|
||||
{},
|
||||
{ width: 100 },
|
||||
{ width: 100 },
|
||||
{},
|
||||
{},
|
||||
{},
|
||||
{ width: 120 },
|
||||
{ width: 100 },
|
||||
{},
|
||||
{},
|
||||
],
|
||||
]
|
||||
|
||||
export const keys = [
|
||||
'bpjs_code',
|
||||
'name',
|
||||
'identity_number',
|
||||
'sip_no',
|
||||
'ihs_number',
|
||||
'phone',
|
||||
'inPatient_itemPrice',
|
||||
'outPatient_itemPrice',
|
||||
'status',
|
||||
'action',
|
||||
]
|
||||
headers: [
|
||||
[
|
||||
{ label: 'Kode JKN' },
|
||||
{ label: 'Nama' },
|
||||
{ label: 'No KTP' },
|
||||
{ label: 'No SIP' },
|
||||
{ label: 'No IHS' },
|
||||
{ label: 'Telpon' },
|
||||
{ label: 'Fee Ranap' },
|
||||
{ label: 'Fee Rajal' },
|
||||
{ label: 'Status' },
|
||||
{ label: '' },
|
||||
],
|
||||
],
|
||||
|
||||
export const delKeyNames: KeyLabel[] = [
|
||||
{ key: 'code', label: 'Kode' },
|
||||
{ key: 'name', label: 'Nama' },
|
||||
]
|
||||
keys: [
|
||||
'bpjs_code',
|
||||
'name',
|
||||
'identity_number',
|
||||
'sip_no',
|
||||
'ihs_number',
|
||||
'phone',
|
||||
'inPatient_itemPrice',
|
||||
'outPatient_itemPrice',
|
||||
'status',
|
||||
'action',
|
||||
],
|
||||
|
||||
export const funcParsed: RecStrFuncUnknown = {
|
||||
name: (rec: unknown): unknown => {
|
||||
const recX = rec as SmallDetailDto
|
||||
return `${recX.frontTitle} ${recX.name} ${recX.endTitle}`.trim()
|
||||
},
|
||||
identity_number: (rec: unknown): unknown => {
|
||||
const recX = rec as SmallDetailDto
|
||||
if (recX.identity_number?.substring(0, 5) === 'BLANK') {
|
||||
return '(TANPA NIK)'
|
||||
}
|
||||
return recX.identity_number
|
||||
},
|
||||
inPatient_itemPrice: (rec: unknown): unknown => {
|
||||
const recX = rec as SmallDetailDto
|
||||
return Number(recX.inPatient_itemPrice.price).toLocaleString('id-ID')
|
||||
},
|
||||
outPatient_itemPrice: (rec: unknown): unknown => {
|
||||
const recX = rec as SmallDetailDto
|
||||
return Number(recX.outPatient_itemPrice.price).toLocaleString('id-ID')
|
||||
},
|
||||
}
|
||||
delKeyNames: [
|
||||
{ key: 'code', label: 'Kode' },
|
||||
{ key: 'name', label: 'Nama' },
|
||||
],
|
||||
|
||||
export const funcComponent: RecStrFuncComponent = {
|
||||
action(rec, idx) {
|
||||
const res: RecComponent = {
|
||||
idx,
|
||||
rec: rec as object,
|
||||
component: action,
|
||||
}
|
||||
return res
|
||||
parses: {
|
||||
name: (rec: unknown): unknown => {
|
||||
const recX = rec as SmallDetailDto
|
||||
return `${recX.frontTitle} ${recX.name} ${recX.endTitle}`.trim()
|
||||
},
|
||||
identity_number: (rec: unknown): unknown => {
|
||||
const recX = rec as SmallDetailDto
|
||||
if (recX.identity_number?.substring(0, 5) === 'BLANK') {
|
||||
return '(TANPA NIK)'
|
||||
}
|
||||
return recX.identity_number
|
||||
},
|
||||
inPatient_itemPrice: (rec: unknown): unknown => {
|
||||
const recX = rec as SmallDetailDto
|
||||
return Number(recX.inPatient_itemPrice.price).toLocaleString('id-ID')
|
||||
},
|
||||
outPatient_itemPrice: (rec: unknown): unknown => {
|
||||
const recX = rec as SmallDetailDto
|
||||
return Number(recX.outPatient_itemPrice.price).toLocaleString('id-ID')
|
||||
},
|
||||
},
|
||||
status(rec, idx) {
|
||||
const res: RecComponent = {
|
||||
idx,
|
||||
rec: rec as object,
|
||||
component: statusBadge,
|
||||
}
|
||||
return res
|
||||
},
|
||||
}
|
||||
|
||||
export const funcHtml: RecStrFuncUnknown = {
|
||||
patient_address(_rec) {
|
||||
return '-'
|
||||
components: {
|
||||
action(rec, idx) {
|
||||
const res: RecComponent = {
|
||||
idx,
|
||||
rec: rec as object,
|
||||
component: action,
|
||||
}
|
||||
return res
|
||||
},
|
||||
status(rec, idx) {
|
||||
const res: RecComponent = {
|
||||
idx,
|
||||
rec: rec as object,
|
||||
component: statusBadge,
|
||||
}
|
||||
return res
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
htmls: {
|
||||
patient_address(_rec) {
|
||||
return '-'
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
<script setup lang="ts">
|
||||
import { cols, funcComponent, funcHtml, funcParsed, header, keys } from './list-cfg'
|
||||
import { config } from './list-cfg'
|
||||
|
||||
defineProps<{
|
||||
data: any[]
|
||||
@@ -8,12 +8,7 @@ defineProps<{
|
||||
|
||||
<template>
|
||||
<PubMyUiDataTable
|
||||
v-bind="config"
|
||||
:rows="data"
|
||||
:cols="cols"
|
||||
:header="header"
|
||||
:keys="keys"
|
||||
:func-parsed="funcParsed"
|
||||
:func-html="funcHtml"
|
||||
:func-component="funcComponent"
|
||||
/>
|
||||
</template>
|
||||
|
||||
@@ -1,11 +1,4 @@
|
||||
import type {
|
||||
Col,
|
||||
KeyLabel,
|
||||
RecComponent,
|
||||
RecStrFuncComponent,
|
||||
RecStrFuncUnknown,
|
||||
Th,
|
||||
} from '~/components/pub/my-ui/data/types'
|
||||
import type { Config, RecComponent } from '~/components/pub/my-ui/data-table'
|
||||
import { defineAsyncComponent } from 'vue'
|
||||
|
||||
type SmallDetailDto = any
|
||||
@@ -17,93 +10,95 @@ const doctorStatus = {
|
||||
1: 'Aktif',
|
||||
}
|
||||
|
||||
export const cols: Col[] = [
|
||||
{ width: 100 },
|
||||
{ width: 250 },
|
||||
{},
|
||||
{ width: 100 },
|
||||
{ width: 100 },
|
||||
{},
|
||||
{},
|
||||
{},
|
||||
{ width: 100 },
|
||||
{ width: 100 },
|
||||
{ width: 100 },
|
||||
{ width: 50 },
|
||||
]
|
||||
|
||||
export const header: Th[][] = [
|
||||
[
|
||||
{ label: 'Kode JKN' },
|
||||
{ label: 'Nama' },
|
||||
{ label: 'No KTP' },
|
||||
{ label: 'No SIP' },
|
||||
{ label: 'No IHS' },
|
||||
{ label: 'Telpon' },
|
||||
{ label: 'Fee Ranap' },
|
||||
{ label: 'Fee Rajal' },
|
||||
{ label: 'Status' },
|
||||
export const config: Config = {
|
||||
cols: [
|
||||
{ width: 100 },
|
||||
{ width: 250 },
|
||||
{},
|
||||
{ width: 100 },
|
||||
{ width: 100 },
|
||||
{},
|
||||
{},
|
||||
{},
|
||||
{ width: 120 },
|
||||
{ width: 100 },
|
||||
{},
|
||||
{},
|
||||
],
|
||||
]
|
||||
|
||||
export const keys = [
|
||||
'bpjs_code',
|
||||
'name',
|
||||
'identity_number',
|
||||
'sip_no',
|
||||
'ihs_number',
|
||||
'phone',
|
||||
'inPatient_itemPrice',
|
||||
'outPatient_itemPrice',
|
||||
'status',
|
||||
'action',
|
||||
]
|
||||
headers: [
|
||||
[
|
||||
{ label: 'Kode JKN' },
|
||||
{ label: 'Nama' },
|
||||
{ label: 'No KTP' },
|
||||
{ label: 'No SIP' },
|
||||
{ label: 'No IHS' },
|
||||
{ label: 'Telpon' },
|
||||
{ label: 'Fee Ranap' },
|
||||
{ label: 'Fee Rajal' },
|
||||
{ label: 'Status' },
|
||||
{ label: '' },
|
||||
],
|
||||
],
|
||||
|
||||
export const delKeyNames: KeyLabel[] = [
|
||||
{ key: 'code', label: 'Kode' },
|
||||
{ key: 'name', label: 'Nama' },
|
||||
]
|
||||
keys: [
|
||||
'bpjs_code',
|
||||
'name',
|
||||
'identity_number',
|
||||
'sip_no',
|
||||
'ihs_number',
|
||||
'phone',
|
||||
'inPatient_itemPrice',
|
||||
'outPatient_itemPrice',
|
||||
'status',
|
||||
'action',
|
||||
],
|
||||
|
||||
export const funcParsed: RecStrFuncUnknown = {
|
||||
name: (rec: unknown): unknown => {
|
||||
console.log(rec)
|
||||
const recX = rec as SmallDetailDto
|
||||
return `${recX.frontTitle} ${recX.name} ${recX.endTitle}`.trim()
|
||||
},
|
||||
identity_number: (rec: unknown): unknown => {
|
||||
const recX = rec as SmallDetailDto
|
||||
if (recX.identity_number?.substring(0, 5) === 'BLANK') {
|
||||
return '(TANPA NIK)'
|
||||
delKeyNames: [
|
||||
{ key: 'code', label: 'Kode' },
|
||||
{ key: 'name', label: 'Nama' },
|
||||
],
|
||||
|
||||
parses: {
|
||||
name: (rec: unknown): unknown => {
|
||||
const recX = rec as SmallDetailDto
|
||||
return `${recX.frontTitle} ${recX.name} ${recX.endTitle}`.trim()
|
||||
},
|
||||
identity_number: (rec: unknown): unknown => {
|
||||
const recX = rec as SmallDetailDto
|
||||
if (recX.identity_number?.substring(0, 5) === 'BLANK') {
|
||||
return '(TANPA NIK)'
|
||||
}
|
||||
return recX.identity_number
|
||||
},
|
||||
inPatient_itemPrice: (rec: unknown): unknown => {
|
||||
const recX = rec as SmallDetailDto
|
||||
return Number(recX.inPatient_itemPrice.price).toLocaleString('id-ID')
|
||||
},
|
||||
outPatient_itemPrice: (rec: unknown): unknown => {
|
||||
const recX = rec as SmallDetailDto
|
||||
return Number(recX.outPatient_itemPrice.price).toLocaleString('id-ID')
|
||||
},
|
||||
status: (rec: unknown): unknown => {
|
||||
const recX = rec as SmallDetailDto
|
||||
return doctorStatus[recX.status_code as keyof typeof doctorStatus]
|
||||
}
|
||||
return recX.identity_number
|
||||
},
|
||||
inPatient_itemPrice: (rec: unknown): unknown => {
|
||||
const recX = rec as SmallDetailDto
|
||||
return Number(recX.inPatient_itemPrice.price).toLocaleString('id-ID')
|
||||
},
|
||||
outPatient_itemPrice: (rec: unknown): unknown => {
|
||||
const recX = rec as SmallDetailDto
|
||||
return Number(recX.outPatient_itemPrice.price).toLocaleString('id-ID')
|
||||
},
|
||||
status: (rec: unknown): unknown => {
|
||||
const recX = rec as SmallDetailDto
|
||||
return doctorStatus[recX.status_code as keyof typeof doctorStatus]
|
||||
},
|
||||
}
|
||||
|
||||
export const funcComponent: RecStrFuncComponent = {
|
||||
action(rec, idx) {
|
||||
const res: RecComponent = {
|
||||
idx,
|
||||
rec: rec as object,
|
||||
component: action,
|
||||
components: {
|
||||
action(rec, idx) {
|
||||
const res: RecComponent = {
|
||||
idx,
|
||||
rec: rec as object,
|
||||
component: action,
|
||||
}
|
||||
return res
|
||||
}
|
||||
return res
|
||||
},
|
||||
}
|
||||
|
||||
export const funcHtml: RecStrFuncUnknown = {
|
||||
patient_address(_rec) {
|
||||
return '-'
|
||||
htmls: {
|
||||
patient_address(_rec) {
|
||||
return '-'
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<script setup lang="ts">
|
||||
import { cols, funcComponent, funcHtml, funcParsed, header, keys } from './list-cfg'
|
||||
import { config } from './list-cfg'
|
||||
|
||||
defineProps<{
|
||||
data: any[]
|
||||
@@ -8,12 +8,7 @@ defineProps<{
|
||||
|
||||
<template>
|
||||
<PubMyUiDataTable
|
||||
v-bind="config"
|
||||
:rows="data"
|
||||
:cols="cols"
|
||||
:header="header"
|
||||
:keys="keys"
|
||||
:func-parsed="funcParsed"
|
||||
:func-html="funcHtml"
|
||||
:func-component="funcComponent"
|
||||
/>
|
||||
</template>
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
<script setup lang="ts">
|
||||
import Block from '~/components/pub/form/block.vue'
|
||||
import FieldGroup from '~/components/pub/form/field-group.vue'
|
||||
import Field from '~/components/pub/form/field.vue'
|
||||
import Label from '~/components/pub/form/label.vue'
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<form id="entry-form">
|
||||
<div class="mb-5 border-b border-b-slate-300 pb-3 text-lg xl:text-xl">
|
||||
<Icon name="i-lucide-user" class="me-2" />
|
||||
<span class="font-semibold">Tambah</span> Pasien
|
||||
</div>
|
||||
|
||||
<div class="mb-5 border-b border-b-slate-300 pb-3 text-lg xl:text-xl">
|
||||
<Block>
|
||||
<FieldGroup :column="3">
|
||||
<Label>Nama</Label>
|
||||
<Field>
|
||||
<Input type="text" name="name" />
|
||||
</Field>
|
||||
</FieldGroup>
|
||||
<FieldGroup :column="3">
|
||||
<Label>Nama</Label>
|
||||
<Field>
|
||||
<Input type="text" name="name" />
|
||||
</Field>
|
||||
</FieldGroup>
|
||||
<FieldGroup :column="3">
|
||||
<Label>Nomor RM</Label>
|
||||
<Field>
|
||||
<Input type="text" name="name" />
|
||||
</Field>
|
||||
</FieldGroup>
|
||||
<FieldGroup>
|
||||
<Label dynamic>Alamat</Label>
|
||||
<Field>
|
||||
<Input type="text" name="name" />
|
||||
</Field>
|
||||
</FieldGroup>
|
||||
</Block>
|
||||
</div>
|
||||
<div class="my-2 flex justify-end py-2">
|
||||
<PubNavFooterCsd />
|
||||
</div>
|
||||
</form>
|
||||
</template>
|
||||
+2
-21
@@ -1,17 +1,9 @@
|
||||
import type {
|
||||
Col,
|
||||
KeyLabel,
|
||||
RecComponent,
|
||||
RecStrFuncComponent,
|
||||
RecStrFuncUnknown,
|
||||
Th,
|
||||
} from '~/components/pub/my-ui/data/types'
|
||||
import type { Col, KeyLabel, RecComponent, RecStrFuncComponent, RecStrFuncUnknown, Th } from '~/components/pub/my-ui/data/types'
|
||||
import { defineAsyncComponent } from 'vue'
|
||||
|
||||
type SmallDetailDto = any
|
||||
|
||||
const action = defineAsyncComponent(() => import('~/components/pub/my-ui/data/dropdown-action-pdud.vue'))
|
||||
const statusBadge = defineAsyncComponent(() => import('./status-badge.vue'))
|
||||
const action = defineAsyncComponent(() => import('~/components/pub/my-ui/data/dropdown-action-dud.vue'))
|
||||
|
||||
export const cols: Col[] = [
|
||||
{},
|
||||
@@ -111,17 +103,6 @@ export const funcComponent: RecStrFuncComponent = {
|
||||
}
|
||||
return res
|
||||
},
|
||||
status(rec, idx) {
|
||||
if (rec.status === null) {
|
||||
rec.status_code = 0
|
||||
}
|
||||
const res: RecComponent = {
|
||||
idx,
|
||||
rec: rec as object,
|
||||
component: statusBadge,
|
||||
}
|
||||
return res
|
||||
},
|
||||
}
|
||||
|
||||
export const funcHtml: RecStrFuncUnknown = {
|
||||
@@ -0,0 +1,19 @@
|
||||
<script setup lang="ts">
|
||||
import { cols, funcComponent, funcHtml, funcParsed, header, keys } from './list-cfg'
|
||||
|
||||
defineProps<{
|
||||
data: any[]
|
||||
}>()
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<PubMyUiDataTable
|
||||
:rows="data"
|
||||
:cols="cols"
|
||||
:header="header"
|
||||
:keys="keys"
|
||||
:func-parsed="funcParsed"
|
||||
:func-html="funcHtml"
|
||||
:func-component="funcComponent"
|
||||
/>
|
||||
</template>
|
||||
@@ -108,248 +108,246 @@ function onAddSep() {
|
||||
:initial-values="initialValues"
|
||||
>
|
||||
<form id="entry-form" @submit="handleSubmit($event, (values) => onSubmitForm(values, { resetForm }))">
|
||||
<div class="mb-5 border-b border-b-slate-300 pb-3 text-lg xl:text-xl">
|
||||
<div class="flex flex-col justify-between">
|
||||
<div class="p-2">
|
||||
<h2 class="text-md font-semibold">Data Pasien</h2>
|
||||
</div>
|
||||
<div class="my-2 flex gap-6 p-2 text-sm">
|
||||
<span>
|
||||
Sudah pernah terdaftar sebagai pasien?
|
||||
<Button class="bg-primary" size="sm" @click.prevent="emit('click', 'search')">
|
||||
<Icon name="i-lucide-search" class="mr-1" /> Cari Pasien
|
||||
</Button>
|
||||
</span>
|
||||
<span>
|
||||
Belum pernah terdaftar sebagai pasien?
|
||||
<Button class="bg-primary" size="sm" @click.prevent="emit('click', 'add')">
|
||||
<Icon name="i-lucide-plus" class="mr-1" /> Tambah Pasien Baru
|
||||
</Button>
|
||||
</span>
|
||||
</div>
|
||||
<Block :colCount="3">
|
||||
<Cell>
|
||||
<Label label-for="patient_name">Nama Pasien</Label>
|
||||
<Field id="patient_name" :errors="errors">
|
||||
<FormField v-slot="{ componentField }" name="patient_name">
|
||||
<FormItem>
|
||||
<FormControl>
|
||||
<Input
|
||||
id="patient_name"
|
||||
v-bind="componentField"
|
||||
disabled
|
||||
placeholder="Tambah data pasien terlebih dahulu"
|
||||
/>
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
</FormField>
|
||||
</Field>
|
||||
</Cell>
|
||||
|
||||
<!-- NIK -->
|
||||
<Cell :cosSpan="3">
|
||||
<Label label-for="nik">NIK</Label>
|
||||
<Field id="nik" :errors="errors">
|
||||
<FormField v-slot="{ componentField }" name="nik">
|
||||
<FormItem>
|
||||
<FormControl>
|
||||
<Input id="nik" v-bind="componentField" disabled placeholder="Otomatis" />
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
</FormField>
|
||||
</Field>
|
||||
</Cell>
|
||||
<Cell>
|
||||
<Label label-for="rm">No. RM</Label>
|
||||
<Field id="rm" :errors="errors">
|
||||
<FormField v-slot="{ componentField }" name="rm">
|
||||
<FormItem>
|
||||
<FormControl>
|
||||
<Input id="rm" v-bind="componentField" disabled placeholder="RM99222" />
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
</FormField>
|
||||
</Field>
|
||||
</Cell>
|
||||
</Block>
|
||||
<Separator />
|
||||
|
||||
<div class="p-2">
|
||||
<h2 class="text-md font-semibold">Data Kunjungan</h2>
|
||||
</div>
|
||||
|
||||
<Block :colCount="3">
|
||||
<!-- Dokter (Combobox) -->
|
||||
<Cell :cosSpan="3">
|
||||
<Label label-for="doctor_id">Dokter</Label>
|
||||
<Field id="doctor_id" :errors="errors">
|
||||
<FormField v-slot="{ componentField }" name="doctor_id">
|
||||
<FormItem>
|
||||
<FormControl>
|
||||
<Combobox id="doctor_id" v-bind="componentField" :items="doctorOpts" />
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
</FormField>
|
||||
</Field>
|
||||
</Cell>
|
||||
|
||||
<!-- Tanggal Daftar (DatePicker) -->
|
||||
<Cell :cosSpan="3">
|
||||
<Label label-for="register_date">Tanggal Daftar</Label>
|
||||
<Field id="register_date" :errors="errors">
|
||||
<FormField v-slot="{ componentField }" name="register_date">
|
||||
<FormItem>
|
||||
<FormControl>
|
||||
<DatepickerSingle v-bind="componentField" placeholder="Pilih tanggal" />
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
</FormField>
|
||||
</Field>
|
||||
</Cell>
|
||||
|
||||
<!-- Jenis Pembayaran (Combobox) -->
|
||||
<Cell :cosSpan="3">
|
||||
<Label label-for="payment_type">Jenis Pembayaran</Label>
|
||||
<Field id="payment_type" :errors="errors">
|
||||
<FormField v-slot="{ componentField }" name="payment_type">
|
||||
<FormItem>
|
||||
<FormControl>
|
||||
<!-- <Combobox id="payment_type" v-bind="componentField" :items="paymentOpts" /> -->
|
||||
<Select id="payment_type" v-bind="componentField" :items="paymentOpts" />
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
</FormField>
|
||||
</Field>
|
||||
</Cell>
|
||||
</Block>
|
||||
|
||||
<Block :colCount="3">
|
||||
<Cell :cosSpan="3">
|
||||
<Label label-for="bpjs_number">Kelompok Peserta</Label>
|
||||
<Field id="bpjs_number" :errors="errors">
|
||||
<FormField v-slot="{ componentField }" name="bpjs_number">
|
||||
<FormItem>
|
||||
<FormControl>
|
||||
<Input
|
||||
id="bpjs_number"
|
||||
v-bind="componentField"
|
||||
placeholder="Pilih jenis pembayaran terlebih dahulu"
|
||||
/>
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
</FormField>
|
||||
</Field>
|
||||
</Cell>
|
||||
|
||||
<!-- No. Kartu BPJS -->
|
||||
<Cell :cosSpan="3">
|
||||
<Label label-for="bpjs_number">No. Kartu BPJS</Label>
|
||||
<Field id="bpjs_number" :errors="errors">
|
||||
<FormField v-slot="{ componentField }" name="bpjs_number">
|
||||
<FormItem>
|
||||
<FormControl>
|
||||
<Input
|
||||
id="bpjs_number"
|
||||
v-bind="componentField"
|
||||
placeholder="Pilih jenis pembayaran terlebih dahulu"
|
||||
/>
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
</FormField>
|
||||
</Field>
|
||||
</Cell>
|
||||
|
||||
<!-- Jenis SEP -->
|
||||
<Cell :cosSpan="3">
|
||||
<Label label-for="sep_type">Jenis SEP</Label>
|
||||
<Field id="sep_type" :errors="errors">
|
||||
<FormField v-slot="{ componentField }" name="sep_type">
|
||||
<FormItem>
|
||||
<FormControl>
|
||||
<Select id="sep_type" v-bind="componentField" :items="sepOpts" />
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
</FormField>
|
||||
</Field>
|
||||
</Cell>
|
||||
</Block>
|
||||
|
||||
<Block :colCount="3">
|
||||
<!-- No. SEP (input + tombol +) -->
|
||||
<Cell :cosSpan="3">
|
||||
<Label label-for="sep_number">No. SEP</Label>
|
||||
<Field id="sep_number" :errors="errors">
|
||||
<FormField v-slot="{ componentField }" name="sep_number">
|
||||
<FormItem>
|
||||
<FormControl>
|
||||
<div class="flex gap-2">
|
||||
<Input
|
||||
id="sep_number"
|
||||
v-bind="componentField"
|
||||
placeholder="Tambah SEP terlebih dahulu"
|
||||
class="flex-1"
|
||||
/>
|
||||
<Button class="bg-primary" size="sm" variant="outline" @click.prevent="onAddSep">+</Button>
|
||||
</div>
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
</FormField>
|
||||
</Field>
|
||||
</Cell>
|
||||
|
||||
<!-- Dokumen SEP (file) -->
|
||||
<Cell :cosSpan="3">
|
||||
<Label label-for="sep_file">Dokumen SEP</Label>
|
||||
<Field id="sep_file" :errors="errors">
|
||||
<FormField v-slot="{ componentField }" name="sep_file">
|
||||
<FormItem>
|
||||
<FormControl>
|
||||
<div class="flex items-center gap-2">
|
||||
<input ref="sepFileInput" type="file" class="hidden" @change="onSepFileChange" />
|
||||
<Button class="bg-primary" size="sm" variant="ghost" @click.prevent="pickSepFile"
|
||||
>Pilih Berkas</Button
|
||||
>
|
||||
<Input readonly v-bind="componentField" placeholder="Unggah dokumen SEP" />
|
||||
</div>
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
</FormField>
|
||||
</Field>
|
||||
</Cell>
|
||||
|
||||
<!-- Dokumen SIPP (file) -->
|
||||
<Cell :cosSpan="3" labelSize="thin">
|
||||
<Label label-for="sipp_file">Dokumen SIPP</Label>
|
||||
<Field id="sipp_file" :errors="errors">
|
||||
<FormField v-slot="{ componentField }" name="sipp_file">
|
||||
<FormItem>
|
||||
<FormControl>
|
||||
<div class="flex items-center gap-2">
|
||||
<input ref="sippFileInput" type="file" class="hidden" @change="onSippFileChange" />
|
||||
<Button class="bg-primary" size="sm" variant="ghost" @click.prevent="pickSippFile"
|
||||
>Pilih Berkas</Button
|
||||
>
|
||||
<Input readonly v-bind="componentField" placeholder="Unggah dokumen SIPP" />
|
||||
</div>
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
</FormField>
|
||||
</Field>
|
||||
</Cell>
|
||||
</Block>
|
||||
<div class="flex flex-col justify-between">
|
||||
<div class="mb-2 2xl:mb-3 text-sm 2xl:text-base font-semibold">
|
||||
Data Pasien
|
||||
</div>
|
||||
<div class="flex gap-6 mb-2 2xl:mb-2">
|
||||
<span>
|
||||
Sudah pernah terdaftar sebagai pasien?
|
||||
<Button class="bg-primary" size="sm" @click.prevent="emit('click', 'search')">
|
||||
<Icon name="i-lucide-search" class="mr-1" /> Cari Pasien
|
||||
</Button>
|
||||
</span>
|
||||
<span>
|
||||
Belum pernah terdaftar sebagai pasien?
|
||||
<Button class="bg-primary" size="sm" @click.prevent="emit('click', 'add')">
|
||||
<Icon name="i-lucide-plus" class="mr-1" /> Tambah Pasien Baru
|
||||
</Button>
|
||||
</span>
|
||||
</div>
|
||||
<Block :colCount="3">
|
||||
<Cell>
|
||||
<Label label-for="patient_name">Nama Pasien</Label>
|
||||
<Field id="patient_name" :errors="errors">
|
||||
<FormField v-slot="{ componentField }" name="patient_name">
|
||||
<FormItem>
|
||||
<FormControl>
|
||||
<Input
|
||||
id="patient_name"
|
||||
v-bind="componentField"
|
||||
disabled
|
||||
placeholder="Tambah data pasien terlebih dahulu"
|
||||
/>
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
</FormField>
|
||||
</Field>
|
||||
</Cell>
|
||||
|
||||
<!-- NIK -->
|
||||
<Cell :cosSpan="3">
|
||||
<Label label-for="nik">NIK</Label>
|
||||
<Field id="nik" :errors="errors">
|
||||
<FormField v-slot="{ componentField }" name="nik">
|
||||
<FormItem>
|
||||
<FormControl>
|
||||
<Input id="nik" v-bind="componentField" disabled placeholder="Otomatis" />
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
</FormField>
|
||||
</Field>
|
||||
</Cell>
|
||||
<Cell>
|
||||
<Label label-for="rm">No. RM</Label>
|
||||
<Field id="rm" :errors="errors">
|
||||
<FormField v-slot="{ componentField }" name="rm">
|
||||
<FormItem>
|
||||
<FormControl>
|
||||
<Input id="rm" v-bind="componentField" disabled placeholder="RM99222" />
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
</FormField>
|
||||
</Field>
|
||||
</Cell>
|
||||
</Block>
|
||||
|
||||
<Separator class="my-4 2xl:my-5" />
|
||||
|
||||
<div class="mb-2 2xl:mb-3 text-sm 2xl:text-base font-semibold">
|
||||
Data Kunjungan
|
||||
</div>
|
||||
<Block :colCount="3">
|
||||
<!-- Dokter (Combobox) -->
|
||||
<Cell :cosSpan="3">
|
||||
<Label label-for="doctor_id">Dokter</Label>
|
||||
<Field id="doctor_id" :errors="errors">
|
||||
<FormField v-slot="{ componentField }" name="doctor_id">
|
||||
<FormItem>
|
||||
<FormControl>
|
||||
<Combobox id="doctor_id" v-bind="componentField" :items="doctorOpts" />
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
</FormField>
|
||||
</Field>
|
||||
</Cell>
|
||||
|
||||
<!-- Tanggal Daftar (DatePicker) -->
|
||||
<Cell :cosSpan="3">
|
||||
<Label label-for="register_date">Tanggal Daftar</Label>
|
||||
<Field id="register_date" :errors="errors">
|
||||
<FormField v-slot="{ componentField }" name="register_date">
|
||||
<FormItem>
|
||||
<FormControl>
|
||||
<DatepickerSingle v-bind="componentField" placeholder="Pilih tanggal" />
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
</FormField>
|
||||
</Field>
|
||||
</Cell>
|
||||
|
||||
<!-- Jenis Pembayaran (Combobox) -->
|
||||
<Cell :cosSpan="3">
|
||||
<Label label-for="payment_type">Jenis Pembayaran</Label>
|
||||
<Field id="payment_type" :errors="errors">
|
||||
<FormField v-slot="{ componentField }" name="payment_type">
|
||||
<FormItem>
|
||||
<FormControl>
|
||||
<!-- <Combobox id="payment_type" v-bind="componentField" :items="paymentOpts" /> -->
|
||||
<Select id="payment_type" v-bind="componentField" :items="paymentOpts" />
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
</FormField>
|
||||
</Field>
|
||||
</Cell>
|
||||
</Block>
|
||||
|
||||
<Block :colCount="3">
|
||||
<Cell :cosSpan="3">
|
||||
<Label label-for="bpjs_number">Kelompok Peserta</Label>
|
||||
<Field id="bpjs_number" :errors="errors">
|
||||
<FormField v-slot="{ componentField }" name="bpjs_number">
|
||||
<FormItem>
|
||||
<FormControl>
|
||||
<Input
|
||||
id="bpjs_number"
|
||||
v-bind="componentField"
|
||||
placeholder="Pilih jenis pembayaran terlebih dahulu"
|
||||
/>
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
</FormField>
|
||||
</Field>
|
||||
</Cell>
|
||||
|
||||
<!-- No. Kartu BPJS -->
|
||||
<Cell :cosSpan="3">
|
||||
<Label label-for="bpjs_number">No. Kartu BPJS</Label>
|
||||
<Field id="bpjs_number" :errors="errors">
|
||||
<FormField v-slot="{ componentField }" name="bpjs_number">
|
||||
<FormItem>
|
||||
<FormControl>
|
||||
<Input
|
||||
id="bpjs_number"
|
||||
v-bind="componentField"
|
||||
placeholder="Pilih jenis pembayaran terlebih dahulu"
|
||||
/>
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
</FormField>
|
||||
</Field>
|
||||
</Cell>
|
||||
|
||||
<!-- Jenis SEP -->
|
||||
<Cell :cosSpan="3">
|
||||
<Label label-for="sep_type">Jenis SEP</Label>
|
||||
<Field id="sep_type" :errors="errors">
|
||||
<FormField v-slot="{ componentField }" name="sep_type">
|
||||
<FormItem>
|
||||
<FormControl>
|
||||
<Select id="sep_type" v-bind="componentField" :items="sepOpts" />
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
</FormField>
|
||||
</Field>
|
||||
</Cell>
|
||||
</Block>
|
||||
|
||||
<Block :colCount="3">
|
||||
<!-- No. SEP (input + tombol +) -->
|
||||
<Cell :cosSpan="3">
|
||||
<Label label-for="sep_number">No. SEP</Label>
|
||||
<Field id="sep_number" :errors="errors">
|
||||
<FormField v-slot="{ componentField }" name="sep_number">
|
||||
<FormItem>
|
||||
<FormControl>
|
||||
<div class="flex gap-2">
|
||||
<Input
|
||||
id="sep_number"
|
||||
v-bind="componentField"
|
||||
placeholder="Tambah SEP terlebih dahulu"
|
||||
class="flex-1"
|
||||
/>
|
||||
<Button class="bg-primary" size="sm" variant="outline" @click.prevent="onAddSep">+</Button>
|
||||
</div>
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
</FormField>
|
||||
</Field>
|
||||
</Cell>
|
||||
|
||||
<!-- Dokumen SEP (file) -->
|
||||
<Cell :cosSpan="3">
|
||||
<Label label-for="sep_file">Dokumen SEP</Label>
|
||||
<Field id="sep_file" :errors="errors">
|
||||
<FormField v-slot="{ componentField }" name="sep_file">
|
||||
<FormItem>
|
||||
<FormControl>
|
||||
<div class="flex items-center gap-2">
|
||||
<input ref="sepFileInput" type="file" class="hidden" @change="onSepFileChange" />
|
||||
<Button class="bg-primary" size="sm" variant="ghost" @click.prevent="pickSepFile"
|
||||
>Pilih Berkas</Button
|
||||
>
|
||||
<Input readonly v-bind="componentField" placeholder="Unggah dokumen SEP" />
|
||||
</div>
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
</FormField>
|
||||
</Field>
|
||||
</Cell>
|
||||
|
||||
<!-- Dokumen SIPP (file) -->
|
||||
<Cell :cosSpan="3" labelSize="thin">
|
||||
<Label label-for="sipp_file">Dokumen SIPP</Label>
|
||||
<Field id="sipp_file" :errors="errors">
|
||||
<FormField v-slot="{ componentField }" name="sipp_file">
|
||||
<FormItem>
|
||||
<FormControl>
|
||||
<div class="flex items-center gap-2">
|
||||
<input ref="sippFileInput" type="file" class="hidden" @change="onSippFileChange" />
|
||||
<Button class="bg-primary" size="sm" variant="ghost" @click.prevent="pickSippFile"
|
||||
>Pilih Berkas</Button
|
||||
>
|
||||
<Input readonly v-bind="componentField" placeholder="Unggah dokumen SIPP" />
|
||||
</div>
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
</FormField>
|
||||
</Field>
|
||||
</Cell>
|
||||
</Block>
|
||||
</div>
|
||||
</form>
|
||||
</Form>
|
||||
|
||||
@@ -0,0 +1,104 @@
|
||||
import type { Config, RecComponent } from '~/components/pub/my-ui/data-table'
|
||||
import { defineAsyncComponent } from 'vue'
|
||||
import type { Encounter } from '~/models/encounter'
|
||||
import { educationCodes, genderCodes } from '~/lib/constants'
|
||||
import { getAge } from '~/lib/date'
|
||||
|
||||
type SmallDetailDto = Encounter
|
||||
|
||||
const action = defineAsyncComponent(() => import('~/components/pub/my-ui/data/dropdown-action-pdud.vue'))
|
||||
const statusBadge = defineAsyncComponent(() => import('./status-badge.vue'))
|
||||
|
||||
export const config: Config = {
|
||||
cols: [
|
||||
{},
|
||||
{},
|
||||
{},
|
||||
{ width: 160 },
|
||||
{},
|
||||
{ width: 70 },
|
||||
{ },
|
||||
{ width: 50 },
|
||||
],
|
||||
|
||||
headers: [
|
||||
[
|
||||
{ label: 'Nama' },
|
||||
{ label: 'Rekam Medis' },
|
||||
{ label: 'KTP' },
|
||||
{ label: 'Tgl Lahir / Umur' },
|
||||
{ label: 'JK' },
|
||||
{ label: 'Pendidikan' },
|
||||
{ label: 'Status', classVal: '!text-center' },
|
||||
{ label: '' },
|
||||
],
|
||||
],
|
||||
|
||||
keys: [
|
||||
'patient.person.name',
|
||||
'patient.number',
|
||||
'patient.person.residentIdentityNumber',
|
||||
'birth_date',
|
||||
'gender',
|
||||
'education',
|
||||
'status',
|
||||
'action',
|
||||
],
|
||||
|
||||
delKeyNames: [
|
||||
{ key: 'code', label: 'Kode' },
|
||||
{ key: 'name', label: 'Nama' },
|
||||
],
|
||||
|
||||
parses: {
|
||||
gender: (rec: unknown): unknown => {
|
||||
const recX = rec as Encounter
|
||||
if (recX.patient?.person?.gender_code) {
|
||||
return genderCodes[recX.patient.person.gender_code]
|
||||
}
|
||||
return '-'
|
||||
},
|
||||
education: (rec: unknown): unknown => {
|
||||
const recX = rec as SmallDetailDto
|
||||
if (recX.patient?.person?.education_code) {
|
||||
return educationCodes[recX.patient.person.education_code]
|
||||
}
|
||||
return '-'
|
||||
},
|
||||
},
|
||||
|
||||
components: {
|
||||
action(rec, idx) {
|
||||
const res: RecComponent = {
|
||||
idx,
|
||||
rec: rec as object,
|
||||
component: action,
|
||||
}
|
||||
return res
|
||||
},
|
||||
status(rec, idx) {
|
||||
const recX = rec as Encounter
|
||||
if (!recX.status_code) {
|
||||
recX.status_code = 'new'
|
||||
}
|
||||
const res: RecComponent = {
|
||||
idx,
|
||||
rec: recX,
|
||||
component: statusBadge,
|
||||
}
|
||||
return res
|
||||
},
|
||||
},
|
||||
|
||||
htmls: {
|
||||
birth_date: (rec: unknown): unknown => {
|
||||
const recX = rec as Encounter
|
||||
if (recX.patient?.person?.birthDate) {
|
||||
return '' +
|
||||
'<div>' + (recX.patient.person.birthDate as string).substring(0, 10) + ' / </div>' +
|
||||
getAge(recX.patient.person.birthDate as string).extFormat
|
||||
}
|
||||
return '-'
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -1,19 +1,14 @@
|
||||
<script setup lang="ts">
|
||||
import { cols, funcComponent, funcHtml, funcParsed, header, keys } from './list-cfg'
|
||||
import { config } from './list.cfg'
|
||||
|
||||
defineProps<{
|
||||
const props = defineProps<{
|
||||
data: any[]
|
||||
}>()
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<PubMyUiDataTable
|
||||
v-bind="config"
|
||||
:rows="data"
|
||||
:cols="cols"
|
||||
:header="header"
|
||||
:keys="keys"
|
||||
:func-parsed="funcParsed"
|
||||
:func-html="funcHtml"
|
||||
:func-component="funcComponent"
|
||||
/>
|
||||
</template>
|
||||
|
||||
@@ -0,0 +1,73 @@
|
||||
<script setup lang="ts">
|
||||
import AssesmentFunctionList from './assesment-function/list.vue'
|
||||
|
||||
const props = defineProps<{
|
||||
initialActiveTab: string
|
||||
}>()
|
||||
|
||||
const activeTab = ref(props.initialActiveTab)
|
||||
const emit = defineEmits<{
|
||||
changeTab: [value: string]
|
||||
}>()
|
||||
|
||||
interface TabItem {
|
||||
value: string
|
||||
label: string
|
||||
component?: any
|
||||
props?: Record<string, any>
|
||||
}
|
||||
|
||||
const tabs: TabItem[] = [
|
||||
{ value: 'status', label: 'Status Masuk/Keluar' },
|
||||
{ value: 'early-medical-assessment', label: 'Pengkajian Awal Medis' },
|
||||
{ value: 'rehab-medical-assessment', label: 'Pengkajian Awal Medis Rehabilitasi Medis' },
|
||||
{ value: 'function-assessment', label: 'Asesmen Fungsi', component: AssesmentFunctionList },
|
||||
{ value: 'therapy-protocol', label: 'Protokol Terapi' },
|
||||
{ value: 'education-assessment', label: 'Asesmen Kebutuhan Edukasi' },
|
||||
{ value: 'consent', label: 'General Consent' },
|
||||
{ value: 'patient-note', label: 'CPRJ' },
|
||||
{ value: 'prescription', label: 'Order Obat' },
|
||||
{ value: 'device', label: 'Order Alkes' },
|
||||
{ value: 'mcu-radiology', label: 'Order Radiologi' },
|
||||
{ value: 'mcu-lab-pc', label: 'Order Lab PK' },
|
||||
{ value: 'mcu-lab-micro', label: 'Order Lab Mikro' },
|
||||
{ value: 'mcu-lab-pa', label: 'Order Lab PA' },
|
||||
{ value: 'medical-action', label: 'Order Ruang Tindakan' },
|
||||
{ value: 'mcu-result', label: 'Hasil Penunjang' },
|
||||
{ value: 'consultation', label: 'Konsultasi' },
|
||||
{ value: 'resume', label: 'Resume' },
|
||||
{ value: 'control', label: 'Surat Kontrol' },
|
||||
{ value: 'screening', label: 'Skrinning MPP' },
|
||||
{ value: 'supporting-document', label: 'Upload Dokumen Pendukung' },
|
||||
]
|
||||
|
||||
function changeTab(value: string) {
|
||||
activeTab.value = value;
|
||||
emit('changeTab', value);
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<!-- Tabs -->
|
||||
<div class="mt-4 flex flex-wrap gap-2 rounded-md border bg-white p-4 shadow-sm">
|
||||
<Button
|
||||
v-for="tab in tabs"
|
||||
:key="tab.value"
|
||||
:data-active="activeTab === tab.value"
|
||||
class="rounded-full transition data-[active=false]:bg-gray-100 data-[active=true]:bg-primary data-[active=false]:text-gray-700 data-[active=true]:text-white"
|
||||
@click="changeTab(tab.value)"
|
||||
>
|
||||
{{ tab.label }}
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
<!-- Active Tab Content -->
|
||||
<div class="mt-4 rounded-md border p-4">
|
||||
<component
|
||||
v-if="tabs.find((t) => t.value === activeTab)?.component"
|
||||
:is="tabs.find((t) => t.value === activeTab)?.component"
|
||||
:label="tabs.find((t) => t.value === activeTab)?.label"
|
||||
v-bind="tabs.find((t) => t.value === activeTab)?.props || {}"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
@@ -1,35 +1,50 @@
|
||||
<script setup lang="ts">
|
||||
import * as DE from '~/components/pub/my-ui/doc-entry';
|
||||
import type { Encounter } from '~/models/encounter';
|
||||
|
||||
defineProps<{
|
||||
data: any
|
||||
const props = defineProps<{
|
||||
data: Encounter
|
||||
}>()
|
||||
|
||||
let address = ''
|
||||
if (props.data.patient.person.addresses) {
|
||||
address = props.data.patient.person.addresses.map(a => a.address).join(', ')
|
||||
}
|
||||
|
||||
let dpjp = '';
|
||||
if (props.data.responsible_doctor) {
|
||||
const dp = props.data.responsible_doctor.employee.person
|
||||
dpjp = `${dp.frontTitle} ${dp.name} ${dp.endTitle}`
|
||||
} else if (props.data.appointment_doctor) {
|
||||
dpjp = props.data.appointment_doctor.employee.person.name
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="w-full rounded-md border bg-white dark:bg-neutral-950 p-4 shadow-sm">
|
||||
<!-- Data Pasien -->
|
||||
<h2 class="mb-2 md:text-base 2xl:text-lg font-semibold">{{ 'data.patient.person.name' }} - {{ 'data.patient.number' }}</h2>
|
||||
<h2 class="mb-2 md:text-base 2xl:text-lg font-semibold">{{ data.patient.person.name }} - {{ data.patient.number }}</h2>
|
||||
|
||||
<div class="grid grid-cols-3" >
|
||||
<div>
|
||||
<DE.Block mode="preview" labelSize="large">
|
||||
<DE.Cell>
|
||||
<DE.Label>Tgl. Lahir</DE.Label>
|
||||
<DE.Label class="font-semibold">No. RM</DE.Label>
|
||||
<DE.Field>
|
||||
{{ 'data.patient.person.birthDate' }}
|
||||
{{ data.patient.person.birthDate?.substring(0, 10) }}
|
||||
</DE.Field>
|
||||
</DE.Cell>
|
||||
<DE.Cell>
|
||||
<DE.Label>Jenis Kelamin</DE.Label>
|
||||
<DE.Label class="font-semibold">Jenis Kelamin</DE.Label>
|
||||
<DE.Field>
|
||||
{{ 'data.patient.person.gender_code' }}
|
||||
{{ data.patient.person.gender_code }}
|
||||
</DE.Field>
|
||||
</DE.Cell>
|
||||
<DE.Cell>
|
||||
<DE.Label>Alamat</DE.Label>
|
||||
<DE.Label class="font-semibold">Alamat</DE.Label>
|
||||
<DE.Field>
|
||||
<div v-html="'data.patient.person .addresses[0].address'"></div>
|
||||
<div v-html="address"></div>
|
||||
</DE.Field>
|
||||
</DE.Cell>
|
||||
</DE.Block>
|
||||
@@ -37,21 +52,21 @@ defineProps<{
|
||||
<div>
|
||||
<DE.Block mode="preview" labelSize="large">
|
||||
<DE.Cell>
|
||||
<DE.Label>Tgl. Kunjungan</DE.Label>
|
||||
<DE.Label class="font-semibold">Tgl. Kunjungan</DE.Label>
|
||||
<DE.Field>
|
||||
{{ 'data.date' }}
|
||||
{{ data.visitDate.substring(0, 10) }}
|
||||
</DE.Field>
|
||||
</DE.Cell>
|
||||
<DE.Cell>
|
||||
<DE.Label>Klinik</DE.Label>
|
||||
<DE.Label class="font-semibold">Klinik</DE.Label>
|
||||
<DE.Field>
|
||||
{{ 'data.unit.name' }}
|
||||
{{ data.unit?.name }}
|
||||
</DE.Field>
|
||||
</DE.Cell>
|
||||
<DE.Cell>
|
||||
<DE.Label>DPJP</DE.Label>
|
||||
<DE.Label class="font-semibold">DPJP</DE.Label>
|
||||
<DE.Field>
|
||||
{{ 'data.doctor.name' }}
|
||||
{{ dpjp }}
|
||||
</DE.Field>
|
||||
</DE.Cell>
|
||||
</DE.Block>
|
||||
@@ -59,21 +74,10 @@ defineProps<{
|
||||
<div>
|
||||
<DE.Block mode="preview" labelSize="large">
|
||||
<DE.Cell>
|
||||
<DE.Label>Tgl. Kunjungan</DE.Label>
|
||||
<DE.Field>
|
||||
{{ 'data.date' }}
|
||||
</DE.Field>
|
||||
</DE.Cell>
|
||||
<DE.Cell>
|
||||
<DE.Label>Klinik</DE.Label>
|
||||
<DE.Field>
|
||||
{{ 'data.unit.name' }}
|
||||
</DE.Field>
|
||||
</DE.Cell>
|
||||
<DE.Cell>
|
||||
<DE.Label>DPJP</DE.Label>
|
||||
<DE.Field>
|
||||
{{ 'data.doctor.name' }}
|
||||
<DE.Label position="dynamic" class="!text-base 2xl:!text-lg font-semibold">Billing</DE.Label>
|
||||
<DE.Field class="text-base 2xl:text-lg">
|
||||
Rp. 000.000
|
||||
<!-- {{ data }} -->
|
||||
</DE.Field>
|
||||
</DE.Cell>
|
||||
</DE.Block>
|
||||
|
||||
@@ -1,22 +1,28 @@
|
||||
<script setup lang="ts">
|
||||
import { Badge } from '~/components/pub/ui/badge'
|
||||
import { type Variants, Badge } from '~/components/pub/ui/badge'
|
||||
import { dataStatusCodes } from '~/lib/constants';
|
||||
|
||||
const props = defineProps<{
|
||||
rec: any
|
||||
idx?: number
|
||||
}>()
|
||||
|
||||
const doctorStatus = {
|
||||
0: 'Tidak Aktif',
|
||||
1: 'Aktif',
|
||||
const statusCodeColors: Record<string, Variants> = {
|
||||
new: 'warning',
|
||||
review: 'fresh',
|
||||
process: 'fresh',
|
||||
done: 'positive',
|
||||
canceled: 'destructive',
|
||||
rejected: 'destructive',
|
||||
skiped: 'negative',
|
||||
}
|
||||
|
||||
const statusText = computed(() => {
|
||||
return doctorStatus[props.rec.status_code as keyof typeof doctorStatus]
|
||||
return dataStatusCodes[props.rec.status_code as keyof typeof dataStatusCodes]
|
||||
})
|
||||
|
||||
const badgeVariant = computed(() => {
|
||||
return props.rec.status_code === 1 ? 'default' : 'destructive'
|
||||
return (statusCodeColors[props.rec.status_code as keyof typeof statusCodeColors] || 'default')
|
||||
})
|
||||
</script>
|
||||
|
||||
|
||||
@@ -1,43 +1,57 @@
|
||||
import type { Col, KeyLabel, RecComponent, RecStrFuncComponent, Th } from '~/components/pub/my-ui/data/types'
|
||||
import type { Config, RecComponent } from '~/components/pub/my-ui/data-table'
|
||||
import { defineAsyncComponent } from 'vue'
|
||||
|
||||
type SmallDetailDto = any
|
||||
|
||||
const action = defineAsyncComponent(() => import('~/components/pub/my-ui/data/dropdown-action-dud.vue'))
|
||||
|
||||
export const cols: Col[] = [{ width: 100 }, { width: 250 }, { width: 100 }, { width: 100 }, { width: 50 }]
|
||||
export const config: Config = {
|
||||
cols: [
|
||||
{ width: 100 },
|
||||
{ width: 250 },
|
||||
{ width: 100 },
|
||||
{ width: 100 },
|
||||
{ width: 50 },
|
||||
],
|
||||
|
||||
export const header: Th[][] = [
|
||||
[{ label: 'Kode' }, { label: 'Nama' }, { label: 'Stok' }, { label: 'Satuan' }, { label: '' }],
|
||||
]
|
||||
headers: [
|
||||
[
|
||||
{ label: 'Kode' },
|
||||
{ label: 'Nama' },
|
||||
{ label: 'Stok' },
|
||||
{ label: 'Satuan' },
|
||||
{ label: '' },
|
||||
],
|
||||
],
|
||||
|
||||
export const keys = ['code', 'name', 'stock', 'uom_code', 'action']
|
||||
keys: ['code', 'name', 'stock', 'uom_code', 'action'],
|
||||
|
||||
export const delKeyNames: KeyLabel[] = [
|
||||
{ key: 'code', label: 'Kode' },
|
||||
{ key: 'name', label: 'Nama' },
|
||||
]
|
||||
delKeyNames: [
|
||||
{ key: 'code', label: 'Kode' },
|
||||
{ key: 'name', label: 'Nama' },
|
||||
],
|
||||
|
||||
export const funcParsed: Record<string, (row: any, ...args: any[]) => any> = {
|
||||
name: (rec: unknown): unknown => {
|
||||
const recX = rec as SmallDetailDto
|
||||
return `${recX.name}`.trim()
|
||||
parses: {
|
||||
name: (rec: unknown): unknown => {
|
||||
const recX = rec as SmallDetailDto
|
||||
return `${recX.name}`.trim()
|
||||
},
|
||||
uom_code: (rec: unknown): unknown => {
|
||||
const recX = rec as SmallDetailDto
|
||||
return recX.uom_code
|
||||
},
|
||||
},
|
||||
uom_code: (rec: unknown): unknown => {
|
||||
const recX = rec as SmallDetailDto
|
||||
return recX.uom_code
|
||||
|
||||
components: {
|
||||
action(rec, idx) {
|
||||
const res: RecComponent = {
|
||||
idx,
|
||||
rec: rec as object,
|
||||
component: action,
|
||||
}
|
||||
return res
|
||||
},
|
||||
},
|
||||
|
||||
htmls: {},
|
||||
}
|
||||
|
||||
export const funcComponent: RecStrFuncComponent = {
|
||||
action(rec, idx) {
|
||||
const res: RecComponent = {
|
||||
idx,
|
||||
rec: rec as object,
|
||||
component: action,
|
||||
}
|
||||
return res
|
||||
},
|
||||
}
|
||||
|
||||
export const funcHtml: Record<string, (row: any, ...args: any[]) => any> = {}
|
||||
|
||||
@@ -6,7 +6,7 @@ import PaginationView from '~/components/pub/my-ui/pagination/pagination-view.vu
|
||||
import type { PaginationMeta } from '~/components/pub/my-ui/pagination/pagination.type'
|
||||
|
||||
// Configs
|
||||
import { cols, funcComponent, funcHtml, funcParsed, header, keys } from './list-cfg'
|
||||
import { config } from './list-cfg'
|
||||
|
||||
interface Props {
|
||||
data: any[]
|
||||
@@ -27,14 +27,9 @@ function handlePageChange(page: number) {
|
||||
<template>
|
||||
<div class="space-y-4">
|
||||
<PubMyUiDataTable
|
||||
v-bind="config"
|
||||
:rows="data"
|
||||
:cols="cols"
|
||||
:header="header"
|
||||
:keys="keys"
|
||||
:func-parsed="funcParsed"
|
||||
:func-html="funcHtml"
|
||||
:func-component="funcComponent"
|
||||
/>
|
||||
/>
|
||||
<PaginationView :pagination-meta="paginationMeta" @page-change="handlePageChange" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -1,44 +1,46 @@
|
||||
import type {
|
||||
Col,
|
||||
KeyLabel,
|
||||
RecComponent,
|
||||
RecStrFuncComponent,
|
||||
RecStrFuncUnknown,
|
||||
Th,
|
||||
} from '~/components/pub/my-ui/data/types'
|
||||
import type { Config, RecComponent } from '~/components/pub/my-ui/data-table'
|
||||
import { defineAsyncComponent } from 'vue'
|
||||
|
||||
type SmallDetailDto = any
|
||||
|
||||
const action = defineAsyncComponent(() => import('~/components/pub/my-ui/data/dropdown-action-dud.vue'))
|
||||
|
||||
export const cols: Col[] = [{}, {}, {}, { width: 50 }]
|
||||
export const config: Config = {
|
||||
cols: [{}, {}, {}, { width: 50 }],
|
||||
|
||||
export const header: Th[][] = [[{ label: 'Kode' }, { label: 'Nama' }, { label: 'Gedung' }, { label: '' }]]
|
||||
headers: [
|
||||
[
|
||||
{ label: 'Kode' },
|
||||
{ label: 'Nama' },
|
||||
{ label: 'Gedung' },
|
||||
{ label: '' },
|
||||
],
|
||||
],
|
||||
|
||||
export const keys = ['code', 'name', 'parent', 'action']
|
||||
keys: ['code', 'name', 'parent', 'action'],
|
||||
|
||||
export const delKeyNames: KeyLabel[] = [
|
||||
{ key: 'code', label: 'Kode' },
|
||||
{ key: 'name', label: 'Nama' },
|
||||
]
|
||||
delKeyNames: [
|
||||
{ key: 'code', label: 'Kode' },
|
||||
{ key: 'name', label: 'Nama' },
|
||||
],
|
||||
|
||||
export const funcParsed: RecStrFuncUnknown = {
|
||||
parent: (rec: unknown): unknown => {
|
||||
const recX = rec as SmallDetailDto
|
||||
return recX.parent?.name || '-'
|
||||
parses: {
|
||||
parent: (rec: unknown): unknown => {
|
||||
const recX = rec as SmallDetailDto
|
||||
return recX.parent?.name || '-'
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
export const funcComponent: RecStrFuncComponent = {
|
||||
action(rec, idx) {
|
||||
const res: RecComponent = {
|
||||
idx,
|
||||
rec: rec as object,
|
||||
component: action,
|
||||
}
|
||||
return res
|
||||
components: {
|
||||
action(rec, idx) {
|
||||
const res: RecComponent = {
|
||||
idx,
|
||||
rec: rec as object,
|
||||
component: action,
|
||||
}
|
||||
return res
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
export const funcHtml: RecStrFuncUnknown = {}
|
||||
htmls: {},
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@ import PaginationView from '~/components/pub/my-ui/pagination/pagination-view.vu
|
||||
import type { PaginationMeta } from '~/components/pub/my-ui/pagination/pagination.type'
|
||||
|
||||
// Configs
|
||||
import { cols, funcComponent, funcHtml, funcParsed, header, keys } from './list-cfg'
|
||||
import { config } from './list-cfg'
|
||||
|
||||
interface Props {
|
||||
data: any[]
|
||||
@@ -27,13 +27,8 @@ function handlePageChange(page: number) {
|
||||
<template>
|
||||
<div class="space-y-4">
|
||||
<PubMyUiDataTable
|
||||
v-bind="config"
|
||||
:rows="data"
|
||||
:cols="cols"
|
||||
:header="header"
|
||||
:keys="keys"
|
||||
:func-parsed="funcParsed"
|
||||
:func-html="funcHtml"
|
||||
:func-component="funcComponent"
|
||||
:skeleton-size="paginationMeta?.pageSize"
|
||||
/>
|
||||
<PaginationView :pagination-meta="paginationMeta" @page-change="handlePageChange" />
|
||||
|
||||
+112
-116
@@ -1,11 +1,4 @@
|
||||
import type {
|
||||
Col,
|
||||
KeyLabel,
|
||||
RecComponent,
|
||||
RecStrFuncComponent,
|
||||
RecStrFuncUnknown,
|
||||
Th,
|
||||
} from '~/components/pub/my-ui/data/types'
|
||||
import type { Config, RecComponent } from '~/components/pub/my-ui/data-table'
|
||||
import { defineAsyncComponent } from 'vue'
|
||||
|
||||
type SmallDetailDto = any
|
||||
@@ -13,119 +6,122 @@ type SmallDetailDto = any
|
||||
const action = defineAsyncComponent(() => import('~/components/pub/my-ui/data/dropdown-action-dud.vue'))
|
||||
const statusBadge = defineAsyncComponent(() => import('./status-badge.vue'))
|
||||
|
||||
export const cols: Col[] = [
|
||||
{},
|
||||
{},
|
||||
{},
|
||||
{ width: 100 },
|
||||
{ width: 120 },
|
||||
{},
|
||||
{},
|
||||
{},
|
||||
{ width: 100 },
|
||||
{ width: 100 },
|
||||
{},
|
||||
{ width: 50 },
|
||||
]
|
||||
|
||||
export const header: Th[][] = [
|
||||
[
|
||||
{ label: 'Nama' },
|
||||
{ label: 'Rekam Medis' },
|
||||
{ label: 'KTP' },
|
||||
{ label: 'Tgl Lahir' },
|
||||
{ label: 'Umur' },
|
||||
{ label: 'JK' },
|
||||
{ label: 'Pendidikan' },
|
||||
{ label: 'Status' },
|
||||
{ label: '' },
|
||||
export const config: Config = {
|
||||
cols: [
|
||||
{},
|
||||
{},
|
||||
{},
|
||||
{ width: 100 },
|
||||
{ width: 120 },
|
||||
{},
|
||||
{},
|
||||
{},
|
||||
{ width: 100 },
|
||||
{ width: 100 },
|
||||
{},
|
||||
{ width: 50 },
|
||||
],
|
||||
]
|
||||
|
||||
export const keys = [
|
||||
'name',
|
||||
'medicalRecord_number',
|
||||
'identity_number',
|
||||
'birth_date',
|
||||
'patient_age',
|
||||
'gender',
|
||||
'education',
|
||||
'status',
|
||||
'action',
|
||||
]
|
||||
headers: [
|
||||
[
|
||||
{ label: 'Nama' },
|
||||
{ label: 'Rekam Medis' },
|
||||
{ label: 'KTP' },
|
||||
{ label: 'Tgl Lahir' },
|
||||
{ label: 'Umur' },
|
||||
{ label: 'JK' },
|
||||
{ label: 'Pendidikan' },
|
||||
{ label: 'Status' },
|
||||
{ label: '' },
|
||||
],
|
||||
],
|
||||
|
||||
export const delKeyNames: KeyLabel[] = [
|
||||
{ key: 'code', label: 'Kode' },
|
||||
{ key: 'name', label: 'Nama' },
|
||||
]
|
||||
keys: [
|
||||
'name',
|
||||
'medicalRecord_number',
|
||||
'identity_number',
|
||||
'birth_date',
|
||||
'patient_age',
|
||||
'gender',
|
||||
'education',
|
||||
'status',
|
||||
'action',
|
||||
],
|
||||
|
||||
export const funcParsed: RecStrFuncUnknown = {
|
||||
name: (rec: unknown): unknown => {
|
||||
const recX = rec as SmallDetailDto
|
||||
return `${recX.firstName} ${recX.middleName || ''} ${recX.lastName || ''}`
|
||||
delKeyNames: [
|
||||
{ key: 'code', label: 'Kode' },
|
||||
{ key: 'name', label: 'Nama' },
|
||||
],
|
||||
|
||||
parses: {
|
||||
name: (rec: unknown): unknown => {
|
||||
const recX = rec as SmallDetailDto
|
||||
return `${recX.firstName} ${recX.middleName || ''} ${recX.lastName || ''}`
|
||||
},
|
||||
identity_number: (rec: unknown): unknown => {
|
||||
const recX = rec as SmallDetailDto
|
||||
if (recX.identity_number?.substring(0, 5) === 'BLANK') {
|
||||
return '(TANPA NIK)'
|
||||
}
|
||||
return recX.identity_number
|
||||
},
|
||||
birth_date: (rec: unknown): unknown => {
|
||||
const recX = rec as SmallDetailDto
|
||||
if (typeof recX.birth_date == 'object' && recX.birth_date) {
|
||||
return (recX.birth_date as Date).toLocaleDateString()
|
||||
} else if (typeof recX.birth_date == 'string') {
|
||||
return (recX.birth_date as string).substring(0, 10)
|
||||
}
|
||||
return recX.birth_date
|
||||
},
|
||||
patient_age: (rec: unknown): unknown => {
|
||||
const recX = rec as SmallDetailDto
|
||||
return recX.birth_date?.split('T')[0]
|
||||
},
|
||||
gender: (rec: unknown): unknown => {
|
||||
const recX = rec as SmallDetailDto
|
||||
if (typeof recX?.gender_code !== 'number' && recX?.gender_code !== '') {
|
||||
return 'Tidak Diketahui'
|
||||
}
|
||||
return recX.gender_code
|
||||
},
|
||||
education: (rec: unknown): unknown => {
|
||||
const recX = rec as SmallDetailDto
|
||||
if (typeof recX.education_code == 'number' && recX.education_code >= 0) {
|
||||
return recX.education_code
|
||||
} else if (typeof recX.education_code) {
|
||||
return recX.education_code
|
||||
}
|
||||
return '-'
|
||||
},
|
||||
},
|
||||
identity_number: (rec: unknown): unknown => {
|
||||
const recX = rec as SmallDetailDto
|
||||
if (recX.identity_number?.substring(0, 5) === 'BLANK') {
|
||||
return '(TANPA NIK)'
|
||||
}
|
||||
return recX.identity_number
|
||||
|
||||
components: {
|
||||
action(rec, idx) {
|
||||
const res: RecComponent = {
|
||||
idx,
|
||||
rec: rec as object,
|
||||
component: action,
|
||||
}
|
||||
return res
|
||||
},
|
||||
status(rec, idx) {
|
||||
const recX = rec as SmallDetailDto
|
||||
if (recX.status_code === null) {
|
||||
recX.status_code = 0
|
||||
}
|
||||
const res: RecComponent = {
|
||||
idx,
|
||||
rec: rec as object,
|
||||
component: statusBadge,
|
||||
}
|
||||
return res
|
||||
},
|
||||
},
|
||||
birth_date: (rec: unknown): unknown => {
|
||||
const recX = rec as SmallDetailDto
|
||||
if (typeof recX.birth_date == 'object' && recX.birth_date) {
|
||||
return (recX.birth_date as Date).toLocaleDateString()
|
||||
} else if (typeof recX.birth_date == 'string') {
|
||||
return (recX.birth_date as string).substring(0, 10)
|
||||
}
|
||||
return recX.birth_date
|
||||
},
|
||||
patient_age: (rec: unknown): unknown => {
|
||||
const recX = rec as SmallDetailDto
|
||||
return recX.birth_date?.split('T')[0]
|
||||
},
|
||||
gender: (rec: unknown): unknown => {
|
||||
const recX = rec as SmallDetailDto
|
||||
if (typeof recX?.gender_code !== 'number' && recX?.gender_code !== '') {
|
||||
return 'Tidak Diketahui'
|
||||
}
|
||||
return recX.gender_code
|
||||
},
|
||||
education: (rec: unknown): unknown => {
|
||||
const recX = rec as SmallDetailDto
|
||||
if (typeof recX.education_code == 'number' && recX.education_code >= 0) {
|
||||
return recX.education_code
|
||||
} else if (typeof recX.education_code) {
|
||||
return recX.education_code
|
||||
}
|
||||
return '-'
|
||||
},
|
||||
}
|
||||
|
||||
export const funcComponent: RecStrFuncComponent = {
|
||||
action(rec, idx) {
|
||||
const res: RecComponent = {
|
||||
idx,
|
||||
rec: rec as object,
|
||||
component: action,
|
||||
}
|
||||
return res
|
||||
},
|
||||
status(rec, idx) {
|
||||
if (rec.status === null) {
|
||||
rec.status_code = 0
|
||||
}
|
||||
const res: RecComponent = {
|
||||
idx,
|
||||
rec: rec as object,
|
||||
component: statusBadge,
|
||||
}
|
||||
return res
|
||||
},
|
||||
}
|
||||
|
||||
export const funcHtml: RecStrFuncUnknown = {
|
||||
patient_address(_rec) {
|
||||
return '-'
|
||||
|
||||
htmls: {
|
||||
patient_address(_rec) {
|
||||
return '-'
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<script setup lang="ts">
|
||||
import { cols, funcComponent, funcHtml, funcParsed, header, keys } from './list-cfg'
|
||||
import { config } from './list-cfg'
|
||||
|
||||
defineProps<{
|
||||
data: any[]
|
||||
@@ -8,12 +8,7 @@ defineProps<{
|
||||
|
||||
<template>
|
||||
<PubMyUiDataTable
|
||||
v-bind="config"
|
||||
:rows="data"
|
||||
:cols="cols"
|
||||
:header="header"
|
||||
:keys="keys"
|
||||
:func-parsed="funcParsed"
|
||||
:func-html="funcHtml"
|
||||
:func-component="funcComponent"
|
||||
/>
|
||||
</template>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<script setup lang="ts">
|
||||
import { cols, funcComponent, funcHtml, funcParsed, header, keys } from './list-cfg'
|
||||
import { config } from './list-cfg'
|
||||
|
||||
defineProps<{ data: any[] }>()
|
||||
const modelValue = defineModel<any | null>()
|
||||
@@ -8,13 +8,8 @@ const modelValue = defineModel<any | null>()
|
||||
<template>
|
||||
<PubMyUiDataTable
|
||||
v-model="modelValue"
|
||||
v-bind="config"
|
||||
select-mode="multi"
|
||||
:rows="data"
|
||||
:cols="cols"
|
||||
:header="header"
|
||||
:keys="keys"
|
||||
:func-parsed="funcParsed"
|
||||
:func-html="funcHtml"
|
||||
:func-component="funcComponent"
|
||||
/>
|
||||
</template>
|
||||
|
||||
@@ -1,51 +1,53 @@
|
||||
import type {
|
||||
Col,
|
||||
KeyLabel,
|
||||
RecComponent,
|
||||
RecStrFuncComponent,
|
||||
RecStrFuncUnknown,
|
||||
Th,
|
||||
} from '~/components/pub/my-ui/data/types'
|
||||
import type { Config, RecComponent } from '~/components/pub/my-ui/data-table'
|
||||
import { defineAsyncComponent } from 'vue'
|
||||
|
||||
type SmallDetailDto = any
|
||||
|
||||
const action = defineAsyncComponent(() => import('~/components/pub/my-ui/data/dropdown-action-ud.vue'))
|
||||
|
||||
export const cols: Col[] = [{}, {}, {}, { width: 50 }]
|
||||
export const config: Config = {
|
||||
cols: [{}, {}, {}, { width: 50 }],
|
||||
|
||||
export const header: Th[][] = [[{ label: 'Kode' }, { label: 'Nama' }, { label: 'Encounter Class' }, { label: '' }]]
|
||||
headers: [
|
||||
[
|
||||
{ label: 'Kode' },
|
||||
{ label: 'Nama' },
|
||||
{ label: 'Encounter Class' },
|
||||
{ label: '' },
|
||||
],
|
||||
],
|
||||
|
||||
export const keys = ['code', 'name', 'encounterClass_code', 'action']
|
||||
keys: ['code', 'name', 'encounterClass_code', 'action'],
|
||||
|
||||
export const delKeyNames: KeyLabel[] = [
|
||||
{ key: 'code', label: 'Kode' },
|
||||
{ key: 'name', label: 'Nama' },
|
||||
]
|
||||
delKeyNames: [
|
||||
{ key: 'code', label: 'Kode' },
|
||||
{ key: 'name', label: 'Nama' },
|
||||
],
|
||||
|
||||
export const funcParsed: RecStrFuncUnknown = {
|
||||
name: (rec: unknown): unknown => {
|
||||
const recX = rec as SmallDetailDto
|
||||
return `${recX.name}`.trim()
|
||||
parses: {
|
||||
name: (rec: unknown): unknown => {
|
||||
const recX = rec as SmallDetailDto
|
||||
return `${recX.name}`.trim()
|
||||
},
|
||||
},
|
||||
|
||||
components: {
|
||||
action(rec, idx) {
|
||||
const res: RecComponent = {
|
||||
idx,
|
||||
rec: rec as object,
|
||||
component: action,
|
||||
props: {
|
||||
size: 'sm',
|
||||
},
|
||||
}
|
||||
return res
|
||||
},
|
||||
},
|
||||
|
||||
htmls: {
|
||||
patient_address(_rec) {
|
||||
return '-'
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
export const funcComponent: RecStrFuncComponent = {
|
||||
action(rec, idx) {
|
||||
const res: RecComponent = {
|
||||
idx,
|
||||
rec: rec as object,
|
||||
component: action,
|
||||
props: {
|
||||
size: 'sm',
|
||||
},
|
||||
}
|
||||
return res
|
||||
},
|
||||
}
|
||||
|
||||
export const funcHtml: RecStrFuncUnknown = {
|
||||
patient_address(_rec) {
|
||||
return '-'
|
||||
},
|
||||
}
|
||||
@@ -6,7 +6,7 @@ import PaginationView from '~/components/pub/my-ui/pagination/pagination-view.vu
|
||||
import type { PaginationMeta } from '~/components/pub/my-ui/pagination/pagination.type'
|
||||
|
||||
// Configs
|
||||
import { cols, funcComponent, funcHtml, funcParsed, header, keys } from './list-cfg'
|
||||
import { config } from './list-cfg'
|
||||
|
||||
interface Props {
|
||||
data: any[]
|
||||
@@ -27,13 +27,8 @@ function handlePageChange(page: number) {
|
||||
<template>
|
||||
<div class="space-y-4">
|
||||
<PubMyUiDataTable
|
||||
v-bind="config"
|
||||
:rows="data"
|
||||
:cols="cols"
|
||||
:header="header"
|
||||
:keys="keys"
|
||||
:func-parsed="funcParsed"
|
||||
:func-html="funcHtml"
|
||||
:func-component="funcComponent"
|
||||
:skeleton-size="paginationMeta?.pageSize"
|
||||
/>
|
||||
<PaginationView :pagination-meta="paginationMeta" @page-change="handlePageChange" />
|
||||
|
||||
@@ -0,0 +1,106 @@
|
||||
<script setup lang="ts">
|
||||
import type { FormErrors } from '~/types/error'
|
||||
import { toTypedSchema } from '@vee-validate/zod'
|
||||
import Block from '~/components/pub/my-ui/form/block.vue'
|
||||
import Combobox from '~/components/pub/my-ui/combobox/combobox.vue'
|
||||
import FieldGroup from '~/components/pub/my-ui/form/field-group.vue'
|
||||
import Field from '~/components/pub/my-ui/form/field.vue'
|
||||
import Label from '~/components/pub/my-ui/form/label.vue'
|
||||
import { educationCodes, genderCodes, occupationCodes, religionCodes, relationshipCodes } from '~/lib/constants'
|
||||
import { mapToComboboxOptList } from '~/lib/utils'
|
||||
import { Form } from '~/components/pub/ui/form'
|
||||
|
||||
interface DivisionFormData {
|
||||
name: string
|
||||
code: string
|
||||
parentId: string
|
||||
}
|
||||
|
||||
const props = defineProps<{
|
||||
division: {
|
||||
msg: {
|
||||
placeholder: string
|
||||
search: string
|
||||
empty: string
|
||||
}
|
||||
}
|
||||
items: {
|
||||
value: string
|
||||
label: string
|
||||
code: string
|
||||
}[]
|
||||
schema: any
|
||||
initialValues?: Partial<DivisionFormData>
|
||||
errors?: FormErrors
|
||||
}>()
|
||||
|
||||
const emit = defineEmits<{
|
||||
submit: [values: DivisionFormData, resetForm: () => void]
|
||||
cancel: [resetForm: () => void]
|
||||
}>()
|
||||
|
||||
const relationshipOpts = mapToComboboxOptList(relationshipCodes)
|
||||
const educationOpts = mapToComboboxOptList(educationCodes)
|
||||
const occupationOpts = mapToComboboxOptList(occupationCodes)
|
||||
const genderOpts = mapToComboboxOptList(genderCodes)
|
||||
|
||||
const formSchema = toTypedSchema(props.schema)
|
||||
|
||||
// Form submission handler
|
||||
function onSubmitForm(values: any, { resetForm }: { resetForm: () => void }) {
|
||||
const formData: DivisionFormData = {
|
||||
name: values.name || '',
|
||||
code: values.code || '',
|
||||
parentId: values.parentId || '',
|
||||
}
|
||||
emit('submit', formData, resetForm)
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Form
|
||||
v-slot="{ handleSubmit, resetForm }"
|
||||
as=""
|
||||
keep-values
|
||||
:validation-schema="formSchema"
|
||||
:initial-values="initialValues"
|
||||
>
|
||||
<form id="entry-form" @submit="handleSubmit($event, (values) => onSubmitForm(values, { resetForm }))">
|
||||
<div class="mb-5 border-b border-b-slate-300 pb-3 text-lg xl:text-xl">
|
||||
<div class="flex flex-col justify-between">
|
||||
<Block>
|
||||
<!-- Specialist -->
|
||||
<FieldGroup :column="2">
|
||||
<Label label-for="specialist_id">Specialist</Label>
|
||||
<Field id="specialist_id" :errors="errors">
|
||||
<FormField v-slot="{ componentField }" name="specialist_id">
|
||||
<FormItem>
|
||||
<FormControl>
|
||||
<Combobox id="specialist_id" v-bind="componentField" :items="genderOpts" />
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
</FormField>
|
||||
</Field>
|
||||
</FieldGroup>
|
||||
|
||||
<!-- Subpecialist -->
|
||||
<FieldGroup :column="2">
|
||||
<Label label-for="subspecialist_id">Subspecialist</Label>
|
||||
<Field id="subspecialist_id" :errors="errors">
|
||||
<FormField v-slot="{ componentField }" name="subspecialist_id">
|
||||
<FormItem>
|
||||
<FormControl>
|
||||
<Combobox id="subspecialist_id" v-bind="componentField" :items="genderOpts" />
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
</FormField>
|
||||
</Field>
|
||||
</FieldGroup>
|
||||
</Block>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</Form>
|
||||
</template>
|
||||
@@ -1,11 +1,4 @@
|
||||
import type {
|
||||
Col,
|
||||
KeyLabel,
|
||||
RecComponent,
|
||||
RecStrFuncComponent,
|
||||
RecStrFuncUnknown,
|
||||
Th,
|
||||
} from '~/components/pub/my-ui/data/types'
|
||||
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-dud.vue'))
|
||||
@@ -15,32 +8,40 @@ const _doctorStatus = {
|
||||
1: 'Aktif',
|
||||
}
|
||||
|
||||
export const cols: Col[] = [{}, {}, { width: 50 }]
|
||||
export const config: Config = {
|
||||
cols: [{}, {}, { width: 50 }],
|
||||
|
||||
export const header: Th[][] = [[{ label: 'Kode' }, { label: 'Nama' }, { label: 'Aksi' }]]
|
||||
headers: [
|
||||
[
|
||||
{ label: 'Kode' },
|
||||
{ label: 'Nama' },
|
||||
{ label: 'Aksi' },
|
||||
],
|
||||
],
|
||||
|
||||
export const keys = ['code', 'name', 'action']
|
||||
keys: ['code', 'name', 'action'],
|
||||
|
||||
export const delKeyNames: KeyLabel[] = [
|
||||
{ key: 'code', label: 'Kode' },
|
||||
{ key: 'name', label: 'Nama' },
|
||||
]
|
||||
delKeyNames: [
|
||||
{ key: 'code', label: 'Kode' },
|
||||
{ key: 'name', label: 'Nama' },
|
||||
],
|
||||
|
||||
export const funcParsed: RecStrFuncUnknown = {}
|
||||
parses: {},
|
||||
|
||||
export const funcComponent: RecStrFuncComponent = {
|
||||
action(rec, idx) {
|
||||
const res: RecComponent = {
|
||||
idx,
|
||||
rec: rec as object,
|
||||
component: action,
|
||||
}
|
||||
return res
|
||||
},
|
||||
}
|
||||
|
||||
export const funcHtml: RecStrFuncUnknown = {
|
||||
patient_address(_rec) {
|
||||
return '-'
|
||||
components: {
|
||||
action(rec, idx) {
|
||||
const res: RecComponent = {
|
||||
idx,
|
||||
rec: rec as object,
|
||||
component: action,
|
||||
}
|
||||
return res
|
||||
},
|
||||
},
|
||||
|
||||
htmls: {
|
||||
patient_address(_rec) {
|
||||
return '-'
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<script setup lang="ts">
|
||||
import { cols, funcComponent, funcHtml, funcParsed, header, keys } from './list-cfg'
|
||||
import { config } from './list-cfg'
|
||||
|
||||
defineProps<{
|
||||
data: any[]
|
||||
@@ -8,12 +8,7 @@ defineProps<{
|
||||
|
||||
<template>
|
||||
<PubMyUiDataTable
|
||||
v-bind="config"
|
||||
:rows="data"
|
||||
:cols="cols"
|
||||
:header="header"
|
||||
:keys="keys"
|
||||
:func-parsed="funcParsed"
|
||||
:func-html="funcHtml"
|
||||
:func-component="funcComponent"
|
||||
/>
|
||||
</template>
|
||||
|
||||
@@ -1,11 +1,4 @@
|
||||
import type {
|
||||
Col,
|
||||
KeyLabel,
|
||||
RecComponent,
|
||||
RecStrFuncComponent,
|
||||
RecStrFuncUnknown,
|
||||
Th,
|
||||
} from '~/components/pub/my-ui/data/types'
|
||||
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-dud.vue'))
|
||||
@@ -15,32 +8,40 @@ const _doctorStatus = {
|
||||
1: 'Aktif',
|
||||
}
|
||||
|
||||
export const cols: Col[] = [{}, {}, { width: 50 }]
|
||||
export const config: Config = {
|
||||
cols: [{}, {}, { width: 50 }],
|
||||
|
||||
export const header: Th[][] = [[{ label: 'Kode' }, { label: 'Nama' }, { label: 'Aksi' }]]
|
||||
headers: [
|
||||
[
|
||||
{ label: 'Kode' },
|
||||
{ label: 'Nama' },
|
||||
{ label: 'Aksi' },
|
||||
],
|
||||
],
|
||||
|
||||
export const keys = ['code', 'name', 'action']
|
||||
keys: ['code', 'name', 'action'],
|
||||
|
||||
export const delKeyNames: KeyLabel[] = [
|
||||
{ key: 'code', label: 'Kode' },
|
||||
{ key: 'name', label: 'Nama' },
|
||||
]
|
||||
delKeyNames: [
|
||||
{ key: 'code', label: 'Kode' },
|
||||
{ key: 'name', label: 'Nama' },
|
||||
],
|
||||
|
||||
export const funcParsed: RecStrFuncUnknown = {}
|
||||
parses: {},
|
||||
|
||||
export const funcComponent: RecStrFuncComponent = {
|
||||
action(rec, idx) {
|
||||
const res: RecComponent = {
|
||||
idx,
|
||||
rec: rec as object,
|
||||
component: action,
|
||||
}
|
||||
return res
|
||||
},
|
||||
}
|
||||
|
||||
export const funcHtml: RecStrFuncUnknown = {
|
||||
patient_address(_rec) {
|
||||
return '-'
|
||||
components: {
|
||||
action(rec, idx) {
|
||||
const res: RecComponent = {
|
||||
idx,
|
||||
rec: rec as object,
|
||||
component: action,
|
||||
}
|
||||
return res
|
||||
},
|
||||
},
|
||||
|
||||
htmls: {
|
||||
patient_address(_rec) {
|
||||
return '-'
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<script setup lang="ts">
|
||||
import { cols, funcComponent, funcHtml, funcParsed, header, keys } from './list-cfg'
|
||||
import { config } from './list-cfg'
|
||||
|
||||
defineProps<{
|
||||
data: any[]
|
||||
@@ -8,12 +8,7 @@ defineProps<{
|
||||
|
||||
<template>
|
||||
<PubMyUiDataTable
|
||||
v-bind="config"
|
||||
:rows="data"
|
||||
:cols="cols"
|
||||
:header="header"
|
||||
:keys="keys"
|
||||
:func-parsed="funcParsed"
|
||||
:func-html="funcHtml"
|
||||
:func-component="funcComponent"
|
||||
/>
|
||||
</template>
|
||||
|
||||
@@ -1,11 +1,4 @@
|
||||
import type {
|
||||
Col,
|
||||
KeyLabel,
|
||||
RecComponent,
|
||||
RecStrFuncComponent,
|
||||
RecStrFuncUnknown,
|
||||
Th,
|
||||
} from '~/components/pub/my-ui/data/types'
|
||||
import type { Config, RecComponent } from '~/components/pub/my-ui/data-table'
|
||||
import { defineAsyncComponent } from 'vue'
|
||||
|
||||
type SmallDetailDto = any
|
||||
@@ -18,97 +11,99 @@ const _doctorStatus = {
|
||||
1: 'Aktif',
|
||||
}
|
||||
|
||||
export const cols: Col[] = [
|
||||
{ width: 100 },
|
||||
{ width: 250 },
|
||||
{},
|
||||
{ width: 100 },
|
||||
{ width: 100 },
|
||||
{},
|
||||
{},
|
||||
{},
|
||||
{ width: 120 },
|
||||
{ width: 100 },
|
||||
{},
|
||||
{},
|
||||
]
|
||||
|
||||
export const header: Th[][] = [
|
||||
[
|
||||
{ label: 'Kode JKN' },
|
||||
{ label: 'Nama' },
|
||||
{ label: 'No KTP' },
|
||||
{ label: 'No SIP' },
|
||||
{ label: 'No IHS' },
|
||||
{ label: 'Telpon' },
|
||||
{ label: 'Fee Ranap' },
|
||||
{ label: 'Fee Rajal' },
|
||||
{ label: 'Status' },
|
||||
{ label: '' },
|
||||
export const config: Config = {
|
||||
cols: [
|
||||
{ width: 100 },
|
||||
{ width: 250 },
|
||||
{},
|
||||
{ width: 100 },
|
||||
{ width: 100 },
|
||||
{},
|
||||
{},
|
||||
{},
|
||||
{ width: 120 },
|
||||
{ width: 100 },
|
||||
{},
|
||||
{},
|
||||
],
|
||||
]
|
||||
|
||||
export const keys = [
|
||||
'bpjs_code',
|
||||
'name',
|
||||
'identity_number',
|
||||
'sip_no',
|
||||
'ihs_number',
|
||||
'phone',
|
||||
'inPatient_itemPrice',
|
||||
'outPatient_itemPrice',
|
||||
'status',
|
||||
'action',
|
||||
]
|
||||
headers: [
|
||||
[
|
||||
{ label: 'Kode JKN' },
|
||||
{ label: 'Nama' },
|
||||
{ label: 'No KTP' },
|
||||
{ label: 'No SIP' },
|
||||
{ label: 'No IHS' },
|
||||
{ label: 'Telpon' },
|
||||
{ label: 'Fee Ranap' },
|
||||
{ label: 'Fee Rajal' },
|
||||
{ label: 'Status' },
|
||||
{ label: '' },
|
||||
],
|
||||
],
|
||||
|
||||
export const delKeyNames: KeyLabel[] = [
|
||||
{ key: 'code', label: 'Kode' },
|
||||
{ key: 'name', label: 'Nama' },
|
||||
]
|
||||
keys: [
|
||||
'bpjs_code',
|
||||
'name',
|
||||
'identity_number',
|
||||
'sip_no',
|
||||
'ihs_number',
|
||||
'phone',
|
||||
'inPatient_itemPrice',
|
||||
'outPatient_itemPrice',
|
||||
'status',
|
||||
'action',
|
||||
],
|
||||
|
||||
export const funcParsed: RecStrFuncUnknown = {
|
||||
name: (rec: unknown): unknown => {
|
||||
const recX = rec as SmallDetailDto
|
||||
return `${recX.frontTitle} ${recX.name} ${recX.endTitle}`.trim()
|
||||
delKeyNames: [
|
||||
{ key: 'code', label: 'Kode' },
|
||||
{ key: 'name', label: 'Nama' },
|
||||
],
|
||||
|
||||
parses: {
|
||||
name: (rec: unknown): unknown => {
|
||||
const recX = rec as SmallDetailDto
|
||||
return `${recX.frontTitle} ${recX.name} ${recX.endTitle}`.trim()
|
||||
},
|
||||
identity_number: (rec: unknown): unknown => {
|
||||
const recX = rec as SmallDetailDto
|
||||
if (recX.identity_number?.substring(0, 5) === 'BLANK') {
|
||||
return '(TANPA NIK)'
|
||||
}
|
||||
return recX.identity_number
|
||||
},
|
||||
inPatient_itemPrice: (rec: unknown): unknown => {
|
||||
const recX = rec as SmallDetailDto
|
||||
return Number(recX.inPatient_itemPrice.price).toLocaleString('id-ID')
|
||||
},
|
||||
outPatient_itemPrice: (rec: unknown): unknown => {
|
||||
const recX = rec as SmallDetailDto
|
||||
return Number(recX.outPatient_itemPrice.price).toLocaleString('id-ID')
|
||||
},
|
||||
},
|
||||
identity_number: (rec: unknown): unknown => {
|
||||
const recX = rec as SmallDetailDto
|
||||
if (recX.identity_number?.substring(0, 5) === 'BLANK') {
|
||||
return '(TANPA NIK)'
|
||||
}
|
||||
return recX.identity_number
|
||||
|
||||
components: {
|
||||
action(rec, idx) {
|
||||
const res: RecComponent = {
|
||||
idx,
|
||||
rec: rec as object,
|
||||
component: action,
|
||||
}
|
||||
return res
|
||||
},
|
||||
status(rec, idx) {
|
||||
const res: RecComponent = {
|
||||
idx,
|
||||
rec: rec as object,
|
||||
component: statusBadge,
|
||||
}
|
||||
return res
|
||||
},
|
||||
},
|
||||
inPatient_itemPrice: (rec: unknown): unknown => {
|
||||
const recX = rec as SmallDetailDto
|
||||
return Number(recX.inPatient_itemPrice.price).toLocaleString('id-ID')
|
||||
},
|
||||
outPatient_itemPrice: (rec: unknown): unknown => {
|
||||
const recX = rec as SmallDetailDto
|
||||
return Number(recX.outPatient_itemPrice.price).toLocaleString('id-ID')
|
||||
},
|
||||
}
|
||||
|
||||
export const funcComponent: RecStrFuncComponent = {
|
||||
action(rec, idx) {
|
||||
const res: RecComponent = {
|
||||
idx,
|
||||
rec: rec as object,
|
||||
component: action,
|
||||
}
|
||||
return res
|
||||
},
|
||||
status(rec, idx) {
|
||||
const res: RecComponent = {
|
||||
idx,
|
||||
rec: rec as object,
|
||||
component: statusBadge,
|
||||
}
|
||||
return res
|
||||
},
|
||||
}
|
||||
|
||||
export const funcHtml: RecStrFuncUnknown = {
|
||||
patient_address(_rec) {
|
||||
return '-'
|
||||
|
||||
htmls: {
|
||||
patient_address(_rec) {
|
||||
return '-'
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<script setup lang="ts">
|
||||
import { cols, funcComponent, funcHtml, funcParsed, header, keys } from './list-cfg'
|
||||
import { config } from './list-cfg'
|
||||
|
||||
defineProps<{
|
||||
data: any[]
|
||||
@@ -8,12 +8,7 @@ defineProps<{
|
||||
|
||||
<template>
|
||||
<PubMyUiDataTable
|
||||
v-bind="config"
|
||||
:rows="data"
|
||||
:cols="cols"
|
||||
:header="header"
|
||||
:keys="keys"
|
||||
:func-parsed="funcParsed"
|
||||
:func-html="funcHtml"
|
||||
:func-component="funcComponent"
|
||||
/>
|
||||
</template>
|
||||
|
||||
@@ -0,0 +1,144 @@
|
||||
<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'
|
||||
import Select from '~/components/pub/my-ui/form/select.vue'
|
||||
|
||||
// Types
|
||||
import type { MedicalActionSrcFormData } from '~/schemas/medical-action-src.schema'
|
||||
import { medicalActionTypeCode } from '~/lib/constants'
|
||||
|
||||
// Helpers
|
||||
import type z from 'zod'
|
||||
import { useForm } from 'vee-validate'
|
||||
import { toTypedSchema } from '@vee-validate/zod'
|
||||
import { mapToComboboxOptList } from '~/lib/utils'
|
||||
|
||||
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 medicalActionTypeOptions = mapToComboboxOptList(medicalActionTypeCode)
|
||||
|
||||
const emit = defineEmits<{
|
||||
submit: [values: MedicalActionSrcFormData, resetForm: () => void]
|
||||
cancel: [resetForm: () => void]
|
||||
}>()
|
||||
|
||||
const { defineField, errors, meta } = useForm({
|
||||
validationSchema: toTypedSchema(props.schema),
|
||||
initialValues: {
|
||||
code: '',
|
||||
name: '',
|
||||
type_code: '',
|
||||
} as Partial<MedicalActionSrcFormData>,
|
||||
})
|
||||
|
||||
const [code, codeAttrs] = defineField('code')
|
||||
const [name, nameAttrs] = defineField('name')
|
||||
const [typeCode, typeCodeAttrs] = defineField('type_code')
|
||||
|
||||
if (props.values) {
|
||||
if (props.values.code !== undefined) code.value = props.values.code
|
||||
if (props.values.name !== undefined) name.value = props.values.name
|
||||
if (props.values.type_code !== undefined) typeCode.value = props.values.type_code
|
||||
}
|
||||
|
||||
const resetForm = () => {
|
||||
code.value = ''
|
||||
name.value = ''
|
||||
typeCode.value = ''
|
||||
}
|
||||
|
||||
function onSubmitForm() {
|
||||
const formData: MedicalActionSrcFormData = {
|
||||
code: code.value || '',
|
||||
name: name.value || '',
|
||||
type_code: typeCode.value || '',
|
||||
}
|
||||
emit('submit', formData, resetForm)
|
||||
}
|
||||
|
||||
function onCancelForm() {
|
||||
emit('cancel', resetForm)
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<form
|
||||
id="form-medical-action-src"
|
||||
@submit.prevent
|
||||
>
|
||||
<Block
|
||||
labelSize="thin"
|
||||
class="!mb-2.5 !pt-0 xl:!mb-3"
|
||||
:colCount="1"
|
||||
>
|
||||
<Cell>
|
||||
<Label height="compact">Kode</Label>
|
||||
<Field :errMessage="errors.code">
|
||||
<Input
|
||||
id="code"
|
||||
v-model="code"
|
||||
v-bind="codeAttrs"
|
||||
:disabled="isLoading || isReadonly"
|
||||
/>
|
||||
</Field>
|
||||
</Cell>
|
||||
<Cell>
|
||||
<Label height="compact">Nama</Label>
|
||||
<Field :errMessage="errors.name">
|
||||
<Input
|
||||
id="name"
|
||||
v-model="name"
|
||||
v-bind="nameAttrs"
|
||||
:disabled="isLoading || isReadonly"
|
||||
/>
|
||||
</Field>
|
||||
</Cell>
|
||||
<Cell>
|
||||
<Label height="compact">Type Kode</Label>
|
||||
<Field :errMessage="errors.name">
|
||||
<Select
|
||||
id="type_code"
|
||||
:is-disabled="isLoading || isReadonly"
|
||||
:items="medicalActionTypeOptions"
|
||||
v-bind="typeCodeAttrs"
|
||||
v-model="typeCode"
|
||||
placeholder="Pilih medical action type"
|
||||
:preserve-order="false"
|
||||
class="text-sm transition-all duration-200 focus:outline-none focus:ring-1 focus:ring-black focus:ring-offset-0"
|
||||
/>
|
||||
</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,32 @@
|
||||
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-dud.vue'))
|
||||
|
||||
export const config: Config = {
|
||||
cols: [{}, {}, {}, { width: 50 }],
|
||||
|
||||
headers: [[{ label: 'Kode' }, { label: 'Nama' }, { label: '' }]],
|
||||
|
||||
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,36 @@
|
||||
<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"
|
||||
:skeleton-size="paginationMeta?.pageSize"
|
||||
/>
|
||||
<PaginationView :pagination-meta="paginationMeta" @page-change="handlePageChange" />
|
||||
</div>
|
||||
</template>
|
||||
@@ -1,37 +1,38 @@
|
||||
import type {
|
||||
Col,
|
||||
KeyLabel,
|
||||
RecComponent,
|
||||
RecStrFuncComponent,
|
||||
RecStrFuncUnknown,
|
||||
Th,
|
||||
} from '~/components/pub/my-ui/data/types'
|
||||
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-dud.vue'))
|
||||
|
||||
export const cols: Col[] = [{}, {}, { width: 50 }]
|
||||
export const config: Config = {
|
||||
cols: [{}, {}, { width: 50 }],
|
||||
|
||||
export const header: Th[][] = [[{ label: 'Kode' }, { label: 'Nama' }, { label: 'Aksi' }]]
|
||||
headers: [
|
||||
[
|
||||
{ label: 'Kode' },
|
||||
{ label: 'Nama' },
|
||||
{ label: 'Aksi' },
|
||||
],
|
||||
],
|
||||
|
||||
export const keys = ['code', 'name', 'action']
|
||||
keys: ['code', 'name', 'action'],
|
||||
|
||||
export const delKeyNames: KeyLabel[] = [
|
||||
{ key: 'code', label: 'Kode' },
|
||||
{ key: 'name', label: 'Nama' },
|
||||
]
|
||||
delKeyNames: [
|
||||
{ key: 'code', label: 'Kode' },
|
||||
{ key: 'name', label: 'Nama' },
|
||||
],
|
||||
|
||||
export const funcParsed: RecStrFuncUnknown = {}
|
||||
parses: {},
|
||||
|
||||
export const funcComponent: RecStrFuncComponent = {
|
||||
action(rec, idx) {
|
||||
const res: RecComponent = {
|
||||
idx,
|
||||
rec: rec as object,
|
||||
component: action,
|
||||
}
|
||||
return res
|
||||
components: {
|
||||
action(rec, idx) {
|
||||
const res: RecComponent = {
|
||||
idx,
|
||||
rec: rec as object,
|
||||
component: action,
|
||||
}
|
||||
return res
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
export const funcHtml: RecStrFuncUnknown = {}
|
||||
htmls: {},
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@ import PaginationView from '~/components/pub/my-ui/pagination/pagination-view.vu
|
||||
import type { PaginationMeta } from '~/components/pub/my-ui/pagination/pagination.type'
|
||||
|
||||
// Configs
|
||||
import { cols, funcComponent, funcHtml, funcParsed, header, keys } from './list-cfg'
|
||||
import { config } from './list-cfg'
|
||||
|
||||
interface Props {
|
||||
data: any[]
|
||||
@@ -27,13 +27,8 @@ function handlePageChange(page: number) {
|
||||
<template>
|
||||
<div class="space-y-4">
|
||||
<PubMyUiDataTable
|
||||
v-bind="config"
|
||||
:rows="data"
|
||||
:cols="cols"
|
||||
:header="header"
|
||||
:keys="keys"
|
||||
:func-parsed="funcParsed"
|
||||
:func-html="funcHtml"
|
||||
:func-component="funcComponent"
|
||||
/>
|
||||
<PaginationView :pagination-meta="paginationMeta" @page-change="handlePageChange" />
|
||||
</div>
|
||||
|
||||
@@ -1,37 +1,38 @@
|
||||
import type {
|
||||
Col,
|
||||
KeyLabel,
|
||||
RecComponent,
|
||||
RecStrFuncComponent,
|
||||
RecStrFuncUnknown,
|
||||
Th,
|
||||
} from '~/components/pub/my-ui/data/types'
|
||||
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-dud.vue'))
|
||||
|
||||
export const cols: Col[] = [{}, {}, { width: 50 }]
|
||||
export const config: Config = {
|
||||
cols: [{}, {}, { width: 50 }],
|
||||
|
||||
export const header: Th[][] = [[{ label: 'Kode' }, { label: 'Nama' }, { label: 'Aksi' }]]
|
||||
headers: [
|
||||
[
|
||||
{ label: 'Kode' },
|
||||
{ label: 'Nama' },
|
||||
{ label: 'Aksi' },
|
||||
],
|
||||
],
|
||||
|
||||
export const keys = ['code', 'name', 'action']
|
||||
keys: ['code', 'name', 'action'],
|
||||
|
||||
export const delKeyNames: KeyLabel[] = [
|
||||
{ key: 'code', label: 'Kode' },
|
||||
{ key: 'name', label: 'Nama' },
|
||||
]
|
||||
delKeyNames: [
|
||||
{ key: 'code', label: 'Kode' },
|
||||
{ key: 'name', label: 'Nama' },
|
||||
],
|
||||
|
||||
export const funcParsed: RecStrFuncUnknown = {}
|
||||
parses: {},
|
||||
|
||||
export const funcComponent: RecStrFuncComponent = {
|
||||
action(rec, idx) {
|
||||
const res: RecComponent = {
|
||||
idx,
|
||||
rec: rec as object,
|
||||
component: action,
|
||||
}
|
||||
return res
|
||||
components: {
|
||||
action(rec, idx) {
|
||||
const res: RecComponent = {
|
||||
idx,
|
||||
rec: rec as object,
|
||||
component: action,
|
||||
}
|
||||
return res
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
export const funcHtml: RecStrFuncUnknown = {}
|
||||
htmls: {},
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@ import PaginationView from '~/components/pub/my-ui/pagination/pagination-view.vu
|
||||
import type { PaginationMeta } from '~/components/pub/my-ui/pagination/pagination.type'
|
||||
|
||||
// Configs
|
||||
import { cols, funcComponent, funcHtml, funcParsed, header, keys } from './list-cfg'
|
||||
import { config } from './list-cfg'
|
||||
|
||||
interface Props {
|
||||
data: any[]
|
||||
@@ -27,13 +27,8 @@ function handlePageChange(page: number) {
|
||||
<template>
|
||||
<div class="space-y-4">
|
||||
<PubMyUiDataTable
|
||||
v-bind="config"
|
||||
:rows="data"
|
||||
:cols="cols"
|
||||
:header="header"
|
||||
:keys="keys"
|
||||
:func-parsed="funcParsed"
|
||||
:func-html="funcHtml"
|
||||
:func-component="funcComponent"
|
||||
/>
|
||||
<PaginationView :pagination-meta="paginationMeta" @page-change="handlePageChange" />
|
||||
</div>
|
||||
|
||||
@@ -85,7 +85,7 @@ function onCancelForm() {
|
||||
|
||||
<template>
|
||||
<form id="form-medicine" @submit.prevent>
|
||||
<Block labelSize="thin" class="!mb-2.5 !pt-0 xl:!mb-3" :colCount="1">
|
||||
<Block class="!mb-2.5 !pt-0 xl:!mb-3" :colCount="1">
|
||||
<Cell>
|
||||
<Label height="">Kode</Label>
|
||||
<Field :errMessage="errors.code">
|
||||
@@ -111,7 +111,7 @@ function onCancelForm() {
|
||||
</Field>
|
||||
</Cell>
|
||||
<Cell>
|
||||
<Label height="compact">Kelompok Obat</Label>
|
||||
<Label >Kelompok Obat</Label>
|
||||
<Field :errMessage="errors.medicineGroup_code">
|
||||
<Select
|
||||
id="medicineGroup_code"
|
||||
@@ -139,7 +139,7 @@ function onCancelForm() {
|
||||
</Field>
|
||||
</Cell>
|
||||
<Cell>
|
||||
<Label height="compact">Satuan</Label>
|
||||
<Label>Satuan</Label>
|
||||
<Field :errMessage="errors.uom_code">
|
||||
<Select
|
||||
id="uom_code"
|
||||
|
||||
@@ -1,59 +1,54 @@
|
||||
import type {
|
||||
Col,
|
||||
KeyLabel,
|
||||
RecComponent,
|
||||
RecStrFuncComponent,
|
||||
RecStrFuncUnknown,
|
||||
Th,
|
||||
} from '~/components/pub/my-ui/data/types'
|
||||
import type { Config, RecComponent } from '~/components/pub/my-ui/data-table'
|
||||
import { defineAsyncComponent } from 'vue'
|
||||
|
||||
type SmallDetailDto = any
|
||||
|
||||
const action = defineAsyncComponent(() => import('~/components/pub/my-ui/data/dropdown-action-dud.vue'))
|
||||
|
||||
export const cols: Col[] = [{}, {}, {}, {}, {}, {}, { width: 50 }]
|
||||
export const config: Config = {
|
||||
cols: [{}, {}, {}, {}, {}, {}, { width: 50 }],
|
||||
|
||||
export const header: Th[][] = [
|
||||
[
|
||||
{ label: 'Kode' },
|
||||
{ label: 'Name' },
|
||||
{ label: 'Golongan' },
|
||||
{ label: 'Metode Pemberian' },
|
||||
{ label: "Satuan" },
|
||||
{ label: 'Stok' },
|
||||
{ label: 'Aksi' },
|
||||
headers: [
|
||||
[
|
||||
{ label: 'Kode' },
|
||||
{ label: 'Name' },
|
||||
{ label: 'Golongan' },
|
||||
{ label: 'Metode Pemberian' },
|
||||
{ label: 'Satuan' },
|
||||
{ label: 'Stok' },
|
||||
{ label: 'Aksi' },
|
||||
],
|
||||
],
|
||||
]
|
||||
|
||||
export const keys = ['code', 'name', 'group', 'method', 'unit', 'stock', 'action']
|
||||
keys: ['code', 'name', 'group', 'method', 'unit', 'stock', 'action'],
|
||||
|
||||
export const delKeyNames: KeyLabel[] = [
|
||||
{ key: 'code', label: 'Kode' },
|
||||
{ key: 'name', label: 'Nama' },
|
||||
]
|
||||
delKeyNames: [
|
||||
{ key: 'code', label: 'Kode' },
|
||||
{ key: 'name', label: 'Nama' },
|
||||
],
|
||||
|
||||
export const funcParsed: RecStrFuncUnknown = {
|
||||
group: (rec: unknown): unknown => {
|
||||
return (rec as SmallDetailDto).medicineGroup?.name || '-'
|
||||
parses: {
|
||||
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).uom?.name || '-'
|
||||
},
|
||||
},
|
||||
method: (rec: unknown): unknown => {
|
||||
return (rec as SmallDetailDto).medicineMethod?.name || '-'
|
||||
},
|
||||
unit: (rec: unknown): unknown => {
|
||||
return (rec as SmallDetailDto).uom?.name || '-'
|
||||
|
||||
components: {
|
||||
action(rec, idx) {
|
||||
const res: RecComponent = {
|
||||
idx,
|
||||
rec: rec as object,
|
||||
component: action,
|
||||
}
|
||||
return res
|
||||
},
|
||||
},
|
||||
|
||||
htmls: {},
|
||||
}
|
||||
|
||||
export const funcComponent: RecStrFuncComponent = {
|
||||
action: (rec: unknown, idx: number): RecComponent => {
|
||||
const res: RecComponent = {
|
||||
idx,
|
||||
rec: rec as object,
|
||||
component: action,
|
||||
}
|
||||
return res
|
||||
},
|
||||
}
|
||||
|
||||
export const funcHtml: RecStrFuncUnknown = {}
|
||||
|
||||
@@ -6,7 +6,7 @@ import PaginationView from '~/components/pub/my-ui/pagination/pagination-view.vu
|
||||
import type { PaginationMeta } from '~/components/pub/my-ui/pagination/pagination.type'
|
||||
|
||||
// Configs
|
||||
import { cols, funcComponent, funcHtml, funcParsed, header, keys } from './list-cfg'
|
||||
import { config } from './list-cfg'
|
||||
|
||||
interface Props {
|
||||
data: any[]
|
||||
@@ -27,13 +27,8 @@ function handlePageChange(page: number) {
|
||||
<template>
|
||||
<div class="space-y-4">
|
||||
<PubMyUiDataTable
|
||||
v-bind="config"
|
||||
:rows="data"
|
||||
:cols="cols"
|
||||
:header="header"
|
||||
:keys="keys"
|
||||
:func-parsed="funcParsed"
|
||||
:func-html="funcHtml"
|
||||
:func-component="funcComponent"
|
||||
/>
|
||||
<PaginationView :pagination-meta="paginationMeta" @page-change="handlePageChange" />
|
||||
</div>
|
||||
|
||||
@@ -1,11 +1,4 @@
|
||||
import type {
|
||||
Col,
|
||||
KeyLabel,
|
||||
RecComponent,
|
||||
RecStrFuncComponent,
|
||||
RecStrFuncUnknown,
|
||||
Th,
|
||||
} from '~/components/pub/my-ui/data/types'
|
||||
import type { Config, RecComponent } from '~/components/pub/my-ui/data-table'
|
||||
import { defineAsyncComponent } from 'vue'
|
||||
|
||||
type SmallDetailDto = any
|
||||
@@ -18,97 +11,99 @@ const _doctorStatus = {
|
||||
1: 'Aktif',
|
||||
}
|
||||
|
||||
export const cols: Col[] = [
|
||||
{ width: 100 },
|
||||
{ width: 250 },
|
||||
{},
|
||||
{ width: 100 },
|
||||
{ width: 100 },
|
||||
{},
|
||||
{},
|
||||
{},
|
||||
{ width: 120 },
|
||||
{ width: 100 },
|
||||
{},
|
||||
{},
|
||||
]
|
||||
|
||||
export const header: Th[][] = [
|
||||
[
|
||||
{ label: 'Kode JKN' },
|
||||
{ label: 'Nama' },
|
||||
{ label: 'No KTP' },
|
||||
{ label: 'No SIP' },
|
||||
{ label: 'No IHS' },
|
||||
{ label: 'Telpon' },
|
||||
{ label: 'Fee Ranap' },
|
||||
{ label: 'Fee Rajal' },
|
||||
{ label: 'Status' },
|
||||
{ label: '' },
|
||||
export const config: Config = {
|
||||
cols: [
|
||||
{ width: 100 },
|
||||
{ width: 250 },
|
||||
{},
|
||||
{ width: 100 },
|
||||
{ width: 100 },
|
||||
{},
|
||||
{},
|
||||
{},
|
||||
{ width: 120 },
|
||||
{ width: 100 },
|
||||
{},
|
||||
{},
|
||||
],
|
||||
]
|
||||
|
||||
export const keys = [
|
||||
'bpjs_code',
|
||||
'name',
|
||||
'identity_number',
|
||||
'sip_no',
|
||||
'ihs_number',
|
||||
'phone',
|
||||
'inPatient_itemPrice',
|
||||
'outPatient_itemPrice',
|
||||
'status',
|
||||
'action',
|
||||
]
|
||||
headers: [
|
||||
[
|
||||
{ label: 'Kode JKN' },
|
||||
{ label: 'Nama' },
|
||||
{ label: 'No KTP' },
|
||||
{ label: 'No SIP' },
|
||||
{ label: 'No IHS' },
|
||||
{ label: 'Telpon' },
|
||||
{ label: 'Fee Ranap' },
|
||||
{ label: 'Fee Rajal' },
|
||||
{ label: 'Status' },
|
||||
{ label: '' },
|
||||
],
|
||||
],
|
||||
|
||||
export const delKeyNames: KeyLabel[] = [
|
||||
{ key: 'code', label: 'Kode' },
|
||||
{ key: 'name', label: 'Nama' },
|
||||
]
|
||||
keys: [
|
||||
'bpjs_code',
|
||||
'name',
|
||||
'identity_number',
|
||||
'sip_no',
|
||||
'ihs_number',
|
||||
'phone',
|
||||
'inPatient_itemPrice',
|
||||
'outPatient_itemPrice',
|
||||
'status',
|
||||
'action',
|
||||
],
|
||||
|
||||
export const funcParsed: RecStrFuncUnknown = {
|
||||
name: (rec: unknown): unknown => {
|
||||
const recX = rec as SmallDetailDto
|
||||
return `${recX.frontTitle} ${recX.name} ${recX.endTitle}`.trim()
|
||||
delKeyNames: [
|
||||
{ key: 'code', label: 'Kode' },
|
||||
{ key: 'name', label: 'Nama' },
|
||||
],
|
||||
|
||||
parses: {
|
||||
name: (rec: unknown): unknown => {
|
||||
const recX = rec as SmallDetailDto
|
||||
return `${recX.frontTitle} ${recX.name} ${recX.endTitle}`.trim()
|
||||
},
|
||||
identity_number: (rec: unknown): unknown => {
|
||||
const recX = rec as SmallDetailDto
|
||||
if (recX.identity_number?.substring(0, 5) === 'BLANK') {
|
||||
return '(TANPA NIK)'
|
||||
}
|
||||
return recX.identity_number
|
||||
},
|
||||
inPatient_itemPrice: (rec: unknown): unknown => {
|
||||
const recX = rec as SmallDetailDto
|
||||
return Number(recX.inPatient_itemPrice.price).toLocaleString('id-ID')
|
||||
},
|
||||
outPatient_itemPrice: (rec: unknown): unknown => {
|
||||
const recX = rec as SmallDetailDto
|
||||
return Number(recX.outPatient_itemPrice.price).toLocaleString('id-ID')
|
||||
},
|
||||
},
|
||||
identity_number: (rec: unknown): unknown => {
|
||||
const recX = rec as SmallDetailDto
|
||||
if (recX.identity_number?.substring(0, 5) === 'BLANK') {
|
||||
return '(TANPA NIK)'
|
||||
}
|
||||
return recX.identity_number
|
||||
|
||||
components: {
|
||||
action(rec, idx) {
|
||||
const res: RecComponent = {
|
||||
idx,
|
||||
rec: rec as object,
|
||||
component: action,
|
||||
}
|
||||
return res
|
||||
},
|
||||
status(rec, idx) {
|
||||
const res: RecComponent = {
|
||||
idx,
|
||||
rec: rec as object,
|
||||
component: statusBadge,
|
||||
}
|
||||
return res
|
||||
},
|
||||
},
|
||||
inPatient_itemPrice: (rec: unknown): unknown => {
|
||||
const recX = rec as SmallDetailDto
|
||||
return Number(recX.inPatient_itemPrice.price).toLocaleString('id-ID')
|
||||
},
|
||||
outPatient_itemPrice: (rec: unknown): unknown => {
|
||||
const recX = rec as SmallDetailDto
|
||||
return Number(recX.outPatient_itemPrice.price).toLocaleString('id-ID')
|
||||
},
|
||||
}
|
||||
|
||||
export const funcComponent: RecStrFuncComponent = {
|
||||
action(rec, idx) {
|
||||
const res: RecComponent = {
|
||||
idx,
|
||||
rec: rec as object,
|
||||
component: action,
|
||||
}
|
||||
return res
|
||||
},
|
||||
status(rec, idx) {
|
||||
const res: RecComponent = {
|
||||
idx,
|
||||
rec: rec as object,
|
||||
component: statusBadge,
|
||||
}
|
||||
return res
|
||||
},
|
||||
}
|
||||
|
||||
export const funcHtml: RecStrFuncUnknown = {
|
||||
patient_address(_rec) {
|
||||
return '-'
|
||||
|
||||
htmls: {
|
||||
patient_address(_rec) {
|
||||
return '-'
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<script setup lang="ts">
|
||||
import { cols, funcComponent, funcHtml, funcParsed, header, keys } from './list-cfg'
|
||||
import { config } from './list-cfg'
|
||||
|
||||
defineProps<{
|
||||
data: any[]
|
||||
@@ -8,12 +8,7 @@ defineProps<{
|
||||
|
||||
<template>
|
||||
<PubMyUiDataTable
|
||||
v-bind="config"
|
||||
:rows="data"
|
||||
:cols="cols"
|
||||
:header="header"
|
||||
:keys="keys"
|
||||
:func-parsed="funcParsed"
|
||||
:func-html="funcHtml"
|
||||
:func-component="funcComponent"
|
||||
/>
|
||||
</template>
|
||||
|
||||
@@ -1,11 +1,4 @@
|
||||
import type {
|
||||
Col,
|
||||
KeyLabel,
|
||||
RecComponent,
|
||||
RecStrFuncComponent,
|
||||
RecStrFuncUnknown,
|
||||
Th,
|
||||
} from '~/components/pub/my-ui/data/types'
|
||||
import type { Config } from '~/components/pub/my-ui/data-table'
|
||||
import { defineAsyncComponent } from 'vue'
|
||||
|
||||
type SmallDetailDto = any
|
||||
@@ -18,97 +11,97 @@ const _doctorStatus = {
|
||||
1: 'Aktif',
|
||||
}
|
||||
|
||||
export const cols: Col[] = [
|
||||
{ width: 100 },
|
||||
{ width: 250 },
|
||||
{},
|
||||
{ width: 100 },
|
||||
{ width: 100 },
|
||||
{},
|
||||
{},
|
||||
{},
|
||||
{ width: 120 },
|
||||
{ width: 100 },
|
||||
{},
|
||||
{},
|
||||
]
|
||||
|
||||
export const header: Th[][] = [
|
||||
[
|
||||
{ label: 'Kode JKN' },
|
||||
{ label: 'Nama' },
|
||||
{ label: 'No KTP' },
|
||||
{ label: 'No SIP' },
|
||||
{ label: 'No IHS' },
|
||||
{ label: 'Telpon' },
|
||||
{ label: 'Fee Ranap' },
|
||||
{ label: 'Fee Rajal' },
|
||||
{ label: 'Status' },
|
||||
{ label: '' },
|
||||
export const config: Config = {
|
||||
cols: [
|
||||
{ width: 100 },
|
||||
{ width: 250 },
|
||||
{},
|
||||
{ width: 100 },
|
||||
{ width: 100 },
|
||||
{},
|
||||
{},
|
||||
{},
|
||||
{ width: 120 },
|
||||
{ width: 100 },
|
||||
{},
|
||||
{},
|
||||
],
|
||||
]
|
||||
|
||||
export const keys = [
|
||||
'bpjs_code',
|
||||
'name',
|
||||
'identity_number',
|
||||
'sip_no',
|
||||
'ihs_number',
|
||||
'phone',
|
||||
'inPatient_itemPrice',
|
||||
'outPatient_itemPrice',
|
||||
'status',
|
||||
'action',
|
||||
]
|
||||
headers: [
|
||||
[
|
||||
{ label: 'Kode JKN' },
|
||||
{ label: 'Nama' },
|
||||
{ label: 'No KTP' },
|
||||
{ label: 'No SIP' },
|
||||
{ label: 'No IHS' },
|
||||
{ label: 'Telpon' },
|
||||
{ label: 'Fee Ranap' },
|
||||
{ label: 'Fee Rajal' },
|
||||
{ label: 'Status' },
|
||||
{ label: '' },
|
||||
],
|
||||
],
|
||||
|
||||
export const delKeyNames: KeyLabel[] = [
|
||||
{ key: 'code', label: 'Kode' },
|
||||
{ key: 'name', label: 'Nama' },
|
||||
]
|
||||
keys: [
|
||||
'bpjs_code',
|
||||
'name',
|
||||
'identity_number',
|
||||
'sip_no',
|
||||
'ihs_number',
|
||||
'phone',
|
||||
'inPatient_itemPrice',
|
||||
'outPatient_itemPrice',
|
||||
'status',
|
||||
'action',
|
||||
],
|
||||
|
||||
export const funcParsed: RecStrFuncUnknown = {
|
||||
name: (rec: unknown): unknown => {
|
||||
const recX = rec as SmallDetailDto
|
||||
return `${recX.frontTitle} ${recX.name} ${recX.endTitle}`.trim()
|
||||
delKeyNames: [
|
||||
{ key: 'code', label: 'Kode' },
|
||||
{ key: 'name', label: 'Nama' },
|
||||
],
|
||||
|
||||
parses: {
|
||||
name: (rec: unknown): unknown => {
|
||||
const recX = rec as SmallDetailDto
|
||||
return `${recX.frontTitle} ${recX.name} ${recX.endTitle}`.trim()
|
||||
},
|
||||
identity_number: (rec: unknown): unknown => {
|
||||
const recX = rec as SmallDetailDto
|
||||
if (recX.identity_number?.substring(0, 5) === 'BLANK') {
|
||||
return '(TANPA NIK)'
|
||||
}
|
||||
return recX.identity_number
|
||||
},
|
||||
inPatient_itemPrice: (rec: unknown): unknown => {
|
||||
const recX = rec as SmallDetailDto
|
||||
return Number(recX.inPatient_itemPrice.price).toLocaleString('id-ID')
|
||||
},
|
||||
outPatient_itemPrice: (rec: unknown): unknown => {
|
||||
const recX = rec as SmallDetailDto
|
||||
return Number(recX.outPatient_itemPrice.price).toLocaleString('id-ID')
|
||||
},
|
||||
},
|
||||
identity_number: (rec: unknown): unknown => {
|
||||
const recX = rec as SmallDetailDto
|
||||
if (recX.identity_number?.substring(0, 5) === 'BLANK') {
|
||||
return '(TANPA NIK)'
|
||||
}
|
||||
return recX.identity_number
|
||||
|
||||
components: {
|
||||
action(rec, idx) {
|
||||
return {
|
||||
idx,
|
||||
rec: rec as object,
|
||||
component: action,
|
||||
}
|
||||
},
|
||||
status(rec, idx) {
|
||||
return {
|
||||
idx,
|
||||
rec: rec as object,
|
||||
component: statusBadge,
|
||||
}
|
||||
},
|
||||
},
|
||||
inPatient_itemPrice: (rec: unknown): unknown => {
|
||||
const recX = rec as SmallDetailDto
|
||||
return Number(recX.inPatient_itemPrice.price).toLocaleString('id-ID')
|
||||
},
|
||||
outPatient_itemPrice: (rec: unknown): unknown => {
|
||||
const recX = rec as SmallDetailDto
|
||||
return Number(recX.outPatient_itemPrice.price).toLocaleString('id-ID')
|
||||
},
|
||||
}
|
||||
|
||||
export const funcComponent: RecStrFuncComponent = {
|
||||
action(rec, idx) {
|
||||
const res: RecComponent = {
|
||||
idx,
|
||||
rec: rec as object,
|
||||
component: action,
|
||||
}
|
||||
return res
|
||||
},
|
||||
status(rec, idx) {
|
||||
const res: RecComponent = {
|
||||
idx,
|
||||
rec: rec as object,
|
||||
component: statusBadge,
|
||||
}
|
||||
return res
|
||||
},
|
||||
}
|
||||
|
||||
export const funcHtml: RecStrFuncUnknown = {
|
||||
patient_address(_rec) {
|
||||
return '-'
|
||||
|
||||
htmls: {
|
||||
patient_address(_rec) {
|
||||
return '-'
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<script setup lang="ts">
|
||||
import { cols, funcComponent, funcHtml, funcParsed, header, keys } from './list-cfg'
|
||||
import { config } from './list-cfg'
|
||||
|
||||
defineProps<{
|
||||
data: any[]
|
||||
@@ -8,12 +8,7 @@ defineProps<{
|
||||
|
||||
<template>
|
||||
<PubMyUiDataTable
|
||||
v-bind="config"
|
||||
:rows="data"
|
||||
:cols="cols"
|
||||
:header="header"
|
||||
:keys="keys"
|
||||
:func-parsed="funcParsed"
|
||||
:func-html="funcHtml"
|
||||
:func-component="funcComponent"
|
||||
/>
|
||||
</template>
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
<script setup lang="ts">
|
||||
import type { FormErrors } from '~/types/error'
|
||||
import Select from '~/components/pub/my-ui/form/select.vue'
|
||||
import { Input } from '~/components/pub/ui/input'
|
||||
import { cn } from '~/lib/utils'
|
||||
|
||||
import * as DE from '~/components/pub/my-ui/doc-entry'
|
||||
|
||||
defineProps<{
|
||||
fieldNameInput: string
|
||||
placeholder: string
|
||||
labelForInput: string
|
||||
errors?: FormErrors
|
||||
class?: string
|
||||
selectClass?: string
|
||||
fieldGroupClass?: string
|
||||
labelClass?: string
|
||||
maxLength?: number
|
||||
isRequired?: boolean
|
||||
}>()
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<DE.Cell :col-span="2">
|
||||
<DE.Label
|
||||
:label-for="fieldNameInput"
|
||||
:is-required="isRequired"
|
||||
>
|
||||
{{ labelForInput }}
|
||||
</DE.Label>
|
||||
|
||||
<DE.Field
|
||||
:id="fieldNameInput"
|
||||
:errors="errors"
|
||||
>
|
||||
<FormField
|
||||
v-slot="{ componentField }"
|
||||
:name="fieldNameInput"
|
||||
>
|
||||
<FormItem>
|
||||
<FormControl>
|
||||
<Input
|
||||
v-bind="componentField"
|
||||
type="text"
|
||||
:placeholder="placeholder"
|
||||
:class="cn('focus:border-primary focus:ring-2 focus:ring-primary focus:ring-offset-0')"
|
||||
/>
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
</FormField>
|
||||
</DE.Field>
|
||||
</DE.Cell>
|
||||
</template>
|
||||
@@ -1,102 +0,0 @@
|
||||
<script setup lang="ts">
|
||||
import type { FormErrors } from '~/types/error'
|
||||
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 { Input } from '~/components/pub/ui/input'
|
||||
import { cn } from '~/lib/utils'
|
||||
|
||||
defineProps<{
|
||||
fieldNameAlias: string
|
||||
fieldNameInput: string
|
||||
placeholder: string
|
||||
labelForAlias: string
|
||||
labelForInput: string
|
||||
errors?: FormErrors
|
||||
class?: string
|
||||
selectClass?: string
|
||||
fieldGroupClass?: string
|
||||
labelClass?: string
|
||||
maxLength?: number
|
||||
isRequired?: boolean
|
||||
}>()
|
||||
|
||||
const aliasOptions = [
|
||||
{ label: 'An', value: 'an' },
|
||||
{ label: 'By.Ny', value: 'byny' },
|
||||
{ label: 'Nn', value: 'nn' },
|
||||
{ label: 'Ny', value: 'ny' },
|
||||
{ label: 'Tn', value: 'tn' },
|
||||
]
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<FieldGroup>
|
||||
<Label
|
||||
:label-for="fieldNameAlias"
|
||||
:is-required="isRequired"
|
||||
>
|
||||
{{ labelForAlias }}
|
||||
</Label>
|
||||
|
||||
<Field
|
||||
:id="fieldNameAlias"
|
||||
:errors="errors"
|
||||
>
|
||||
<FormField
|
||||
v-slot="{ componentField }"
|
||||
:name="fieldNameAlias"
|
||||
>
|
||||
<FormItem>
|
||||
<FormControl>
|
||||
<Select
|
||||
:id="fieldNameAlias"
|
||||
:preserve-order="false"
|
||||
v-bind="componentField"
|
||||
:auto-width="true"
|
||||
:items="aliasOptions"
|
||||
:class="
|
||||
cn(
|
||||
'text-sm transition-all duration-200 focus:outline-none focus:ring-1 focus:ring-black focus:ring-offset-0',
|
||||
selectClass,
|
||||
)
|
||||
"
|
||||
/>
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
</FormField>
|
||||
</Field>
|
||||
</FieldGroup>
|
||||
<FieldGroup>
|
||||
<Label
|
||||
:label-for="fieldNameInput"
|
||||
:is-required="isRequired"
|
||||
>
|
||||
{{ labelForInput }}
|
||||
</Label>
|
||||
|
||||
<Field
|
||||
:id="fieldNameInput"
|
||||
:errors="errors"
|
||||
>
|
||||
<FormField
|
||||
v-slot="{ componentField }"
|
||||
:name="fieldNameInput"
|
||||
>
|
||||
<FormItem>
|
||||
<FormControl>
|
||||
<Input
|
||||
v-bind="componentField"
|
||||
type="text"
|
||||
:placeholder="placeholder"
|
||||
:class="cn('focus:border-primary focus:ring-2 focus:ring-primary focus:ring-offset-0')"
|
||||
/>
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
</FormField>
|
||||
</Field>
|
||||
</FieldGroup>
|
||||
</template>
|
||||
@@ -1,12 +1,11 @@
|
||||
<script setup lang="ts">
|
||||
import type { FormErrors } from '~/types/error'
|
||||
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 { Label as RadioLabel } from '~/components/pub/ui/label'
|
||||
import { RadioGroup, RadioGroupItem } from '~/components/pub/ui/radio-group'
|
||||
import { cn } from '~/lib/utils'
|
||||
|
||||
import * as DE from '~/components/pub/my-ui/doc-entry'
|
||||
|
||||
const props = defineProps<{
|
||||
fieldName?: string
|
||||
label?: string
|
||||
@@ -35,18 +34,19 @@ const genderOptions = [
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<FieldGroup :class="cn('radio-group-field', containerClass)">
|
||||
<Label
|
||||
<DE.Cell :class="cn('radio-group-field', containerClass)">
|
||||
<DE.Label
|
||||
:label-for="fieldName"
|
||||
:is-required="isRequired"
|
||||
height="compact"
|
||||
>
|
||||
{{ label }}
|
||||
</Label>
|
||||
<Field
|
||||
</DE.Label>
|
||||
<DE.Field
|
||||
:id="fieldName"
|
||||
:errors="errors"
|
||||
>
|
||||
class="pt-0.5"
|
||||
>
|
||||
<FormField
|
||||
v-slot="{ componentField }"
|
||||
:name="fieldName"
|
||||
@@ -67,7 +67,7 @@ const genderOptions = [
|
||||
:value="option.value"
|
||||
:class="
|
||||
cn(
|
||||
'relative h-4 w-4 rounded-full border-2 border-muted-foreground before:absolute before:inset-1 before:rounded-full before:bg-primary before:opacity-0 before:transition-opacity data-[state=checked]:border-primary data-[state=checked]:bg-white data-[state=checked]:before:opacity-100 sm:h-5 sm:w-5',
|
||||
'relative h-4 w-4 rounded-full border-muted-foreground before:absolute before:inset-1 before:rounded-full before:bg-primary before:opacity-0 before:transition-opacity data-[state=checked]:border-primary data-[state=checked]:bg-white data-[state=checked]:before:opacity-100 sm:h-5 sm:w-5',
|
||||
containerClass,
|
||||
)
|
||||
"
|
||||
@@ -76,7 +76,7 @@ const genderOptions = [
|
||||
:for="`${fieldName}-${index}`"
|
||||
:class="
|
||||
cn(
|
||||
'cursor-pointer select-none text-xs font-medium leading-none transition-colors hover:text-primary peer-disabled:cursor-not-allowed peer-disabled:opacity-70 sm:text-sm',
|
||||
'cursor-pointer select-none font-normal text-xs leading-none transition-colors hover:text-primary peer-disabled:cursor-not-allowed peer-disabled:opacity-70 sm:text-sm',
|
||||
labelClass,
|
||||
)
|
||||
"
|
||||
@@ -89,6 +89,6 @@ const genderOptions = [
|
||||
<FormMessage class="ml-0 mt-1" />
|
||||
</FormItem>
|
||||
</FormField>
|
||||
</Field>
|
||||
</FieldGroup>
|
||||
</DE.Field>
|
||||
</DE.Cell>
|
||||
</template>
|
||||
|
||||
@@ -1,12 +1,11 @@
|
||||
<script setup lang="ts">
|
||||
import type { FormErrors } from '~/types/error'
|
||||
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 { Label as RadioLabel } from '~/components/pub/ui/label'
|
||||
import { RadioGroup, RadioGroupItem } from '~/components/pub/ui/radio-group'
|
||||
import { cn } from '~/lib/utils'
|
||||
|
||||
import * as DE from '~/components/pub/my-ui/doc-entry'
|
||||
|
||||
const props = defineProps<{
|
||||
fieldName?: string
|
||||
label?: string
|
||||
@@ -35,17 +34,18 @@ const dissabilityOptions = [
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<FieldGroup :class="cn('radio-group-field', containerClass)">
|
||||
<Label
|
||||
<DE.Cell :class="cn('radio-group-field', containerClass)">
|
||||
<DE.Label
|
||||
:label-for="fieldName"
|
||||
:is-required="isRequired"
|
||||
height="compact"
|
||||
>
|
||||
{{ label }}
|
||||
</Label>
|
||||
<Field
|
||||
</DE.Label>
|
||||
<DE.Field
|
||||
:id="fieldName"
|
||||
:errors="errors"
|
||||
class="pt-0.5"
|
||||
>
|
||||
<FormField
|
||||
v-slot="{ componentField }"
|
||||
@@ -67,7 +67,7 @@ const dissabilityOptions = [
|
||||
:value="option.value"
|
||||
:class="
|
||||
cn(
|
||||
'relative h-4 w-4 rounded-full border-2 border-muted-foreground before:absolute before:inset-1 before:rounded-full before:bg-primary before:opacity-0 before:transition-opacity data-[state=checked]:border-primary data-[state=checked]:bg-white data-[state=checked]:before:opacity-100 sm:h-5 sm:w-5',
|
||||
'relative h-4 w-4 rounded-full border-1 border-muted-foreground before:absolute before:inset-1 before:rounded-full before:bg-primary before:opacity-0 before:transition-opacity data-[state=checked]:border-primary data-[state=checked]:bg-white data-[state=checked]:before:opacity-100 sm:h-5 sm:w-5',
|
||||
containerClass,
|
||||
)
|
||||
"
|
||||
@@ -76,7 +76,7 @@ const dissabilityOptions = [
|
||||
:for="`${fieldName}-${index}`"
|
||||
:class="
|
||||
cn(
|
||||
'cursor-pointer select-none text-xs font-medium leading-none transition-colors hover:text-primary peer-disabled:cursor-not-allowed peer-disabled:opacity-70 sm:text-sm',
|
||||
'cursor-pointer select-none text-xs !font-normal leading-none transition-colors hover:text-primary peer-disabled:cursor-not-allowed peer-disabled:opacity-70 sm:text-sm',
|
||||
labelClass,
|
||||
)
|
||||
"
|
||||
@@ -89,6 +89,6 @@ const dissabilityOptions = [
|
||||
<FormMessage class="ml-0 mt-1" />
|
||||
</FormItem>
|
||||
</FormField>
|
||||
</Field>
|
||||
</FieldGroup>
|
||||
</DE.Field>
|
||||
</DE.Cell>
|
||||
</template>
|
||||
|
||||
@@ -1,13 +1,12 @@
|
||||
<script setup lang="ts">
|
||||
import type { FormErrors } from '~/types/error'
|
||||
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 { Label as RadioLabel } from '~/components/pub/ui/label'
|
||||
import { RadioGroup, RadioGroupItem } from '~/components/pub/ui/radio-group'
|
||||
import { genderCodes } from '~/lib/constants'
|
||||
import { cn, mapToComboboxOptList } from '~/lib/utils'
|
||||
|
||||
import * as DE from '~/components/pub/my-ui/doc-entry'
|
||||
|
||||
const props = defineProps<{
|
||||
fieldName?: string
|
||||
label?: string
|
||||
@@ -33,15 +32,15 @@ const genderOptions = mapToComboboxOptList(genderCodes)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<FieldGroup :class="cn('radio-group-field', containerClass)">
|
||||
<Label
|
||||
<DE.Cell :class="cn('radio-group-field', containerClass)" :col-span="4">
|
||||
<DE.Label
|
||||
:label-for="fieldName"
|
||||
:is-required="isRequired"
|
||||
height="compact"
|
||||
>
|
||||
{{ label }}
|
||||
</Label>
|
||||
<Field
|
||||
</DE.Label>
|
||||
<DE.Field
|
||||
:id="fieldName"
|
||||
:errors="errors"
|
||||
>
|
||||
@@ -65,7 +64,7 @@ const genderOptions = mapToComboboxOptList(genderCodes)
|
||||
:value="option.value"
|
||||
:class="
|
||||
cn(
|
||||
'relative h-4 w-4 rounded-full border-2 border-muted-foreground before:absolute before:inset-1 before:rounded-full before:bg-primary before:opacity-0 before:transition-opacity data-[state=checked]:border-primary data-[state=checked]:bg-white data-[state=checked]:before:opacity-100 sm:h-5 sm:w-5',
|
||||
'relative h-4 w-4 rounded-full border-1 border-muted-foreground before:absolute before:inset-1 before:rounded-full before:bg-primary before:opacity-0 before:transition-opacity data-[state=checked]:border-primary data-[state=checked]:bg-white data-[state=checked]:before:opacity-100 sm:h-5 sm:w-5',
|
||||
containerClass,
|
||||
)
|
||||
"
|
||||
@@ -74,7 +73,7 @@ const genderOptions = mapToComboboxOptList(genderCodes)
|
||||
:for="`${fieldName}-${index}`"
|
||||
:class="
|
||||
cn(
|
||||
'cursor-pointer select-none text-xs font-medium leading-none transition-colors hover:text-primary peer-disabled:cursor-not-allowed peer-disabled:opacity-70 sm:text-sm',
|
||||
'cursor-pointer select-none text-xs 2xl:text-sm leading-none transition-colors hover:text-primary peer-disabled:cursor-not-allowed peer-disabled:opacity-70 !font-normal',
|
||||
labelClass,
|
||||
)
|
||||
"
|
||||
@@ -87,6 +86,6 @@ const genderOptions = mapToComboboxOptList(genderCodes)
|
||||
<FormMessage class="ml-0 mt-1" />
|
||||
</FormItem>
|
||||
</FormField>
|
||||
</Field>
|
||||
</FieldGroup>
|
||||
</DE.Field>
|
||||
</DE.Cell>
|
||||
</template>
|
||||
|
||||
@@ -1,12 +1,11 @@
|
||||
<script setup lang="ts">
|
||||
import type { FormErrors } from '~/types/error'
|
||||
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 { Label as RadioLabel } from '~/components/pub/ui/label'
|
||||
import { RadioGroup, RadioGroupItem } from '~/components/pub/ui/radio-group'
|
||||
import { cn } from '~/lib/utils'
|
||||
|
||||
import * as DE from '~/components/pub/my-ui/doc-entry'
|
||||
|
||||
const props = defineProps<{
|
||||
fieldName?: string
|
||||
label?: string
|
||||
@@ -35,17 +34,18 @@ const nationalityOptions = [
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<FieldGroup :class="cn('radio-group-field', containerClass)">
|
||||
<Label
|
||||
<DE.Cell :class="cn('radio-group-field', containerClass)">
|
||||
<DE.Label
|
||||
:label-for="fieldName"
|
||||
:is-required="isRequired"
|
||||
height="compact"
|
||||
>
|
||||
{{ label }}
|
||||
</Label>
|
||||
<Field
|
||||
</DE.Label>
|
||||
<DE.Field
|
||||
:id="fieldName"
|
||||
:errors="errors"
|
||||
class="pt-0.5"
|
||||
>
|
||||
<FormField
|
||||
v-slot="{ componentField }"
|
||||
@@ -67,7 +67,7 @@ const nationalityOptions = [
|
||||
:value="option.value"
|
||||
:class="
|
||||
cn(
|
||||
'relative h-4 w-4 rounded-full border-2 border-muted-foreground before:absolute before:inset-1 before:rounded-full before:bg-primary before:opacity-0 before:transition-opacity data-[state=checked]:border-primary data-[state=checked]:bg-white data-[state=checked]:before:opacity-100 sm:h-5 sm:w-5',
|
||||
'relative h-4 w-4 rounded-full border-1 border-muted-foreground before:absolute before:inset-1 before:rounded-full before:bg-primary before:opacity-0 before:transition-opacity data-[state=checked]:border-primary data-[state=checked]:bg-white data-[state=checked]:before:opacity-100 sm:h-5 sm:w-5',
|
||||
containerClass,
|
||||
)
|
||||
"
|
||||
@@ -76,7 +76,7 @@ const nationalityOptions = [
|
||||
:for="`${fieldName}-${index}`"
|
||||
:class="
|
||||
cn(
|
||||
'cursor-pointer select-none text-xs font-medium leading-none transition-colors hover:text-primary peer-disabled:cursor-not-allowed peer-disabled:opacity-70 sm:text-sm',
|
||||
'cursor-pointer select-none text-xs !font-normal leading-none transition-colors hover:text-primary peer-disabled:cursor-not-allowed peer-disabled:opacity-70 sm:text-sm',
|
||||
labelClass,
|
||||
)
|
||||
"
|
||||
@@ -89,6 +89,6 @@ const nationalityOptions = [
|
||||
<FormMessage class="ml-0 mt-1" />
|
||||
</FormItem>
|
||||
</FormField>
|
||||
</Field>
|
||||
</FieldGroup>
|
||||
</DE.Field>
|
||||
</DE.Cell>
|
||||
</template>
|
||||
|
||||
@@ -0,0 +1,92 @@
|
||||
<script setup lang="ts">
|
||||
import type { FormErrors } from '~/types/error'
|
||||
import { Label as RadioLabel } from '~/components/pub/ui/label'
|
||||
import { RadioGroup, RadioGroupItem } from '~/components/pub/ui/radio-group'
|
||||
import { cn } from '~/lib/utils'
|
||||
|
||||
import * as DE from '~/components/pub/my-ui/doc-entry'
|
||||
|
||||
const props = defineProps<{
|
||||
fieldName?: string
|
||||
label?: string
|
||||
errors?: FormErrors
|
||||
class?: string
|
||||
radioGroupClass?: string
|
||||
radioItemClass?: string
|
||||
labelClass?: string
|
||||
isRequired?: boolean
|
||||
}>()
|
||||
|
||||
const {
|
||||
fieldName = 'isNewBorn',
|
||||
label = 'Status Pasien',
|
||||
errors,
|
||||
class: containerClass,
|
||||
radioGroupClass,
|
||||
radioItemClass,
|
||||
labelClass,
|
||||
} = props
|
||||
|
||||
const newbornOptions = [
|
||||
{ label: 'Ya', value: 'YA' },
|
||||
{ label: 'Tidak', value: 'TIDAK' },
|
||||
]
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<DE.Cell :class="cn('radio-group-field', containerClass)" :col-span="2">
|
||||
<DE.Label
|
||||
:label-for="fieldName"
|
||||
:is-required="isRequired"
|
||||
>
|
||||
{{ label }}
|
||||
</DE.Label>
|
||||
<DE.Field
|
||||
:id="fieldName"
|
||||
:errors="errors"
|
||||
>
|
||||
<FormField
|
||||
v-slot="{ componentField }"
|
||||
:name="fieldName"
|
||||
>
|
||||
<FormItem>
|
||||
<FormControl>
|
||||
<RadioGroup
|
||||
v-bind="componentField"
|
||||
:class="cn('flex flex-row flex-wrap gap-4 sm:gap-6', radioGroupClass)"
|
||||
>
|
||||
<div
|
||||
v-for="(option, index) in newbornOptions"
|
||||
:key="option.value"
|
||||
:class="cn('flex min-w-fit items-center space-x-2 pt-1', radioItemClass)"
|
||||
>
|
||||
<RadioGroupItem
|
||||
:id="`${fieldName}-${index}`"
|
||||
:value="option.value"
|
||||
:class="
|
||||
cn(
|
||||
'relative h-4 w-4 rounded-full border-muted-foreground before:absolute before:inset-1 before:rounded-full before:bg-primary before:opacity-0 before:transition-opacity data-[state=checked]:border-primary data-[state=checked]:bg-white data-[state=checked]:before:opacity-100 sm:h-5 sm:w-5',
|
||||
containerClass,
|
||||
)
|
||||
"
|
||||
/>
|
||||
<RadioLabel
|
||||
:for="`${fieldName}-${index}`"
|
||||
:class="
|
||||
cn(
|
||||
'cursor-pointer select-none text-xs font-normal leading-none transition-colors hover:text-primary peer-disabled:cursor-not-allowed peer-disabled:opacity-70 sm:text-sm',
|
||||
labelClass,
|
||||
)
|
||||
"
|
||||
>
|
||||
{{ option.label }}
|
||||
</RadioLabel>
|
||||
</div>
|
||||
</RadioGroup>
|
||||
</FormControl>
|
||||
<FormMessage class="ml-0 mt-1" />
|
||||
</FormItem>
|
||||
</FormField>
|
||||
</DE.Field>
|
||||
</DE.Cell>
|
||||
</template>
|
||||
@@ -1,11 +1,10 @@
|
||||
<script setup lang="ts">
|
||||
import type { FormErrors } from '~/types/error'
|
||||
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 { cn } from '~/lib/utils'
|
||||
|
||||
import * as DE from '~/components/pub/my-ui/doc-entry'
|
||||
|
||||
const props = defineProps<{
|
||||
fieldName?: string
|
||||
label?: string
|
||||
@@ -40,14 +39,14 @@ const disabilityOptions = [
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<FieldGroup :class="cn('select-field-group', fieldGroupClass, containerClass)">
|
||||
<Label
|
||||
<DE.Cell :class="cn('select-field-group', fieldGroupClass, containerClass)">
|
||||
<DE.Label
|
||||
label-for="fieldName"
|
||||
:is-required="isRequired"
|
||||
>
|
||||
{{ label }}
|
||||
</Label>
|
||||
<Field
|
||||
</DE.Label>
|
||||
<DE.Field
|
||||
:id="fieldName"
|
||||
:errors="errors"
|
||||
:class="cn('select-field-wrapper')"
|
||||
@@ -76,6 +75,6 @@ const disabilityOptions = [
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
</FormField>
|
||||
</Field>
|
||||
</FieldGroup>
|
||||
</DE.Field>
|
||||
</DE.Cell>
|
||||
</template>
|
||||
|
||||
@@ -1,12 +1,11 @@
|
||||
<script setup lang="ts">
|
||||
import type { FormErrors } from '~/types/error'
|
||||
import { differenceInDays, differenceInMonths, differenceInYears, parseISO } from 'date-fns'
|
||||
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 { 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
|
||||
@@ -76,15 +75,15 @@ function calculateAge(birthDate: string | Date | undefined): string {
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<FieldGroup :class="cn('select-field-group', fieldGroupClass, containerClass)">
|
||||
<Label
|
||||
<DE.Cell :class="cn('select-field-group', fieldGroupClass, containerClass)">
|
||||
<DE.Label
|
||||
:label-for="fieldName"
|
||||
:class="cn('select-field-label', labelClass)"
|
||||
:is-required="isRequired"
|
||||
>
|
||||
{{ label }}
|
||||
</Label>
|
||||
<Field
|
||||
</DE.Label>
|
||||
<DE.Field
|
||||
:id="fieldName"
|
||||
:errors="errors"
|
||||
:class="cn('select-field-wrapper')"
|
||||
@@ -113,12 +112,11 @@ function calculateAge(birthDate: string | Date | undefined): string {
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
</FormField>
|
||||
</Field>
|
||||
</FieldGroup>
|
||||
<FieldGroup>
|
||||
<Label label-for="patientAge">Usia</Label>
|
||||
|
||||
<Field id="patientAge">
|
||||
</DE.Field>
|
||||
</DE.Cell>
|
||||
<DE.Cell>
|
||||
<DE.Label label-for="patientAge">Usia</DE.Label>
|
||||
<DE.Field id="patientAge">
|
||||
<FormField name="patientAge">
|
||||
<FormItem>
|
||||
<FormControl>
|
||||
@@ -137,6 +135,6 @@ function calculateAge(birthDate: string | Date | undefined): string {
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
</FormField>
|
||||
</Field>
|
||||
</FieldGroup>
|
||||
</DE.Field>
|
||||
</DE.Cell>
|
||||
</template>
|
||||
|
||||
@@ -1,12 +1,11 @@
|
||||
<script setup lang="ts">
|
||||
import type { FormErrors } from '~/types/error'
|
||||
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 { educationCodes } from '~/lib/constants'
|
||||
import { cn, mapToComboboxOptList } from '~/lib/utils'
|
||||
|
||||
import * as DE from '~/components/pub/my-ui/doc-entry'
|
||||
|
||||
const props = defineProps<{
|
||||
fieldName?: string
|
||||
label?: string
|
||||
@@ -46,15 +45,15 @@ const educationOptions = [
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<FieldGroup :class="cn('select-field-group', fieldGroupClass, containerClass)">
|
||||
<Label
|
||||
<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 }}
|
||||
</Label>
|
||||
<Field
|
||||
</DE.Label>
|
||||
<DE.Field
|
||||
:id="fieldName"
|
||||
:errors="errors"
|
||||
:class="cn('select-field-wrapper')"
|
||||
@@ -83,6 +82,6 @@ const educationOptions = [
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
</FormField>
|
||||
</Field>
|
||||
</FieldGroup>
|
||||
</DE.Field>
|
||||
</DE.Cell>
|
||||
</template>
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
<script setup lang="ts">
|
||||
import type { FormErrors } from '~/types/error'
|
||||
import Combobox from '~/components/pub/my-ui/combobox/combobox.vue'
|
||||
import FieldGroup from '~/components/pub/my-ui/form/field-group.vue'
|
||||
import Field from '~/components/pub/my-ui/form/field.vue'
|
||||
import Label from '~/components/pub/my-ui/form/label.vue'
|
||||
import { cn } from '~/lib/utils'
|
||||
|
||||
import * as DE from '~/components/pub/my-ui/doc-entry'
|
||||
|
||||
const props = defineProps<{
|
||||
fieldName?: string
|
||||
label?: string
|
||||
@@ -49,15 +48,15 @@ const ethnicOptions = [
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<FieldGroup :class="cn('select-field-group', fieldGroupClass, containerClass)">
|
||||
<Label
|
||||
<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 }}
|
||||
</Label>
|
||||
<Field
|
||||
</DE.Label>
|
||||
<DE.Field
|
||||
:id="fieldName"
|
||||
:errors="errors"
|
||||
:class="cn('select-field-wrapper')"
|
||||
@@ -81,6 +80,6 @@ const ethnicOptions = [
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
</FormField>
|
||||
</Field>
|
||||
</FieldGroup>
|
||||
</DE.Field>
|
||||
</DE.Cell>
|
||||
</template>
|
||||
|
||||
@@ -0,0 +1,76 @@
|
||||
<script setup lang="ts">
|
||||
import type { FormErrors } from '~/types/error'
|
||||
import Select from '~/components/pub/my-ui/form/select.vue'
|
||||
import { cn } from '~/lib/utils'
|
||||
|
||||
import * as DE from '~/components/pub/my-ui/doc-entry'
|
||||
|
||||
const props = defineProps<{
|
||||
fieldName?: string
|
||||
label?: string
|
||||
isDisabled?: boolean
|
||||
isRequired?: boolean
|
||||
placeholder?: string
|
||||
errors?: FormErrors
|
||||
class?: string
|
||||
selectClass?: string
|
||||
fieldGroupClass?: string
|
||||
}>()
|
||||
|
||||
const {
|
||||
fieldName = 'disabilityType',
|
||||
placeholder = 'Pilih jenis disabilitas',
|
||||
errors,
|
||||
class: containerClass,
|
||||
selectClass,
|
||||
fieldGroupClass,
|
||||
} = props
|
||||
|
||||
const disabilityOptions = [
|
||||
{ label: 'Laki', value: 'male' },
|
||||
{ label: 'Perempuan', value: 'female' },
|
||||
{ label: 'Tidak Disebutkan', value: 'not-stated' },
|
||||
{ label: 'Tidak Diketahui', value: 'unknown' },
|
||||
]
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<DE.Cell :class="cn('select-field-group', fieldGroupClass, containerClass)">
|
||||
<DE.Label
|
||||
label-for="fieldName"
|
||||
: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>
|
||||
<Select
|
||||
:id="fieldName"
|
||||
:is-disabled="isDisabled"
|
||||
v-bind="componentField"
|
||||
:items="disabilityOptions"
|
||||
:placeholder="placeholder"
|
||||
:preserve-order="false"
|
||||
:class="
|
||||
cn(
|
||||
'text-sm transition-all duration-200 focus:outline-none focus:ring-1 focus:ring-black focus:ring-offset-0',
|
||||
selectClass,
|
||||
)
|
||||
"
|
||||
/>
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
</FormField>
|
||||
</DE.Field>
|
||||
</DE.Cell>
|
||||
</template>
|
||||
@@ -1,10 +1,10 @@
|
||||
<script setup lang="ts">
|
||||
import type { FormErrors } from '~/types/error'
|
||||
import Combobox from '~/components/pub/my-ui/combobox/combobox.vue'
|
||||
import FieldGroup from '~/components/pub/my-ui/form/field-group.vue'
|
||||
import Field from '~/components/pub/my-ui/form/field.vue'
|
||||
import Label from '~/components/pub/my-ui/form/label.vue'
|
||||
import { cn } from '~/lib/utils'
|
||||
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
|
||||
@@ -28,106 +28,20 @@ const {
|
||||
labelClass,
|
||||
} = props
|
||||
|
||||
const jobOptions = [
|
||||
{ label: 'Tidak diketahui', value: 'unknown', priority: 100 },
|
||||
{ label: 'Belum/Tidak Bekerja', value: 'tidak_bekerja', priority: 99 },
|
||||
{ label: 'Mengurus Rumah Tangga', value: 'mengurus_rumah_tangga' },
|
||||
{ label: 'Pelajar/Mahasiswa', value: 'pelajar' },
|
||||
{ label: 'Pensiunan', value: 'pensiunan' },
|
||||
{ label: 'Pegawai Negeri Sipil', value: 'pns' },
|
||||
{ label: 'Tentara Nasional Indonesia', value: 'tni' },
|
||||
{ label: 'Kepolisian RI', value: 'polri' },
|
||||
{ label: 'Perdagangan', value: 'perdagangan' },
|
||||
{ label: 'Petani/Pekebun', value: 'petani' },
|
||||
{ label: 'Peternak', value: 'peternak' },
|
||||
{ label: 'Nelayan/Perikanan', value: 'nelayan' },
|
||||
{ label: 'Industri', value: 'industri' },
|
||||
{ label: 'Konstruksi', value: 'konstruksi' },
|
||||
{ label: 'Transportasi', value: 'transportasi' },
|
||||
{ label: 'Karyawan Swasta', value: 'karyawan_swasta' },
|
||||
{ label: 'Karyawan BUMN', value: 'karyawan_bumn' },
|
||||
{ label: 'Karyawan BUMD', value: 'karyawan_bumd' },
|
||||
{ label: 'Karyawan Honorer', value: 'karyawan_honorer' },
|
||||
{ label: 'Buruh Harian Lepas', value: 'buruh_harian' },
|
||||
{ label: 'Buruh Tani/Perkebunan', value: 'buruh_tani' },
|
||||
{ label: 'Buruh Nelayan/Perikanan', value: 'buruh_nelayan' },
|
||||
{ label: 'Buruh Peternakan', value: 'buruh_peternakan' },
|
||||
{ label: 'Pembantu Rumah Tangga', value: 'pembantu_rumah_tangga' },
|
||||
{ label: 'Tukang Cukur', value: 'tukang_cukur' },
|
||||
{ label: 'Tukang Listrik', value: 'tukang_listrik' },
|
||||
{ label: 'Tukang Batu', value: 'tukang_batu' },
|
||||
{ label: 'Tukang Kayu', value: 'tukang_kayu' },
|
||||
{ label: 'Tukang Sol Sepatu', value: 'tukang_sol_sepatu' },
|
||||
{ label: 'Tukang Jahit', value: 'tukang_jahit' },
|
||||
{ label: 'Tukang Gigi', value: 'tukang_gigi' },
|
||||
{ label: 'Penata Rias', value: 'penata_rias' },
|
||||
{ label: 'Penata Busana', value: 'penata_busana' },
|
||||
{ label: 'Penata Rambut', value: 'penata_rambut' },
|
||||
{ label: 'Mekanik', value: 'mekanik' },
|
||||
{ label: 'Seniman', value: 'seniman' },
|
||||
{ label: 'Tabib', value: 'tabib' },
|
||||
{ label: 'Paraji', value: 'paraji' },
|
||||
{ label: 'Perancang Busana', value: 'perancang_busana' },
|
||||
{ label: 'Penterjemah', value: 'penterjemah' },
|
||||
{ label: 'Imam Mesjid', value: 'imam_mesjid' },
|
||||
{ label: 'Pendeta', value: 'pendeta' },
|
||||
{ label: 'Pastor', value: 'pastor' },
|
||||
{ label: 'Wartawan', value: 'wartawan' },
|
||||
{ label: 'Ustadz/Mubaligh', value: 'ustadz' },
|
||||
{ label: 'Juru Masak', value: 'juru_masak' },
|
||||
{ label: 'Promotor Acara', value: 'promotor' },
|
||||
{ label: 'Anggota DPR-RI', value: 'dpr_ri' },
|
||||
{ label: 'Anggota DPD', value: 'dpd' },
|
||||
{ label: 'Anggota BPK', value: 'bpk' },
|
||||
{ label: 'Presiden', value: 'presiden' },
|
||||
{ label: 'Wakil Presiden', value: 'wakil_presiden' },
|
||||
{ label: 'Anggota Mahkamah Konstitusi', value: 'mk' },
|
||||
{ label: 'Anggota Kabinet/Kementrian', value: 'kabinet' },
|
||||
{ label: 'Duta Besar', value: 'dubes' },
|
||||
{ label: 'Gubernur', value: 'gubernur' },
|
||||
{ label: 'Wakil Gubernur', value: 'wakil_gubernur' },
|
||||
{ label: 'Bupati', value: 'bupati' },
|
||||
{ label: 'Wakil Bupati', value: 'wakil_bupati' },
|
||||
{ label: 'Walikota', value: 'walikota' },
|
||||
{ label: 'Wakil Walikota', value: 'wakil_walikota' },
|
||||
{ label: 'Anggota DPRD Provinsi', value: 'dprd_provinsi' },
|
||||
{ label: 'Anggota DPRD Kabupaten/Kota', value: 'dprd_kabkota' },
|
||||
{ label: 'Dosen', value: 'dosen' },
|
||||
{ label: 'Guru', value: 'guru' },
|
||||
{ label: 'Pilot', value: 'pilot' },
|
||||
{ label: 'Pengacara', value: 'pengacara' },
|
||||
{ label: 'Arsitek', value: 'arsitek' },
|
||||
{ label: 'Akuntan', value: 'akuntan' },
|
||||
{ label: 'Konsultan', value: 'konsultan' },
|
||||
{ label: 'Dokter', value: 'dokter' },
|
||||
{ label: 'Bidan', value: 'bidan' },
|
||||
{ label: 'Apoteker', value: 'apoteker' },
|
||||
{ label: 'Psikiater/Psikolog', value: 'psikolog' },
|
||||
{ label: 'Penyiar Televisi', value: 'penyiar_tv' },
|
||||
{ label: 'Penyiar Radio', value: 'penyiar_radio' },
|
||||
{ label: 'Pelaut', value: 'pelaut' },
|
||||
{ label: 'Sopir', value: 'sopir' },
|
||||
{ label: 'Pialang', value: 'pialang' },
|
||||
{ label: 'Paranormal', value: 'paranormal' },
|
||||
{ label: 'Pedagang', value: 'pedagang' },
|
||||
{ label: 'Perangkat Desa', value: 'perangkat_desa' },
|
||||
{ label: 'Kepala Desa', value: 'kepala_desa' },
|
||||
{ label: 'Biarawati', value: 'biarawati' },
|
||||
{ label: 'Wiraswasta', value: 'wiraswasta' },
|
||||
{ label: 'Lainnya', value: 'lainnya', priority: -100 },
|
||||
]
|
||||
// Generate job options from constants, sama seperti pola genderCodes
|
||||
const jobOptions = mapToComboboxOptList(occupationCodes)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<FieldGroup :class="cn('select-field-group', fieldGroupClass, containerClass)">
|
||||
<Label
|
||||
<DE.Cell :class="cn('select-field-group', fieldGroupClass, containerClass)">
|
||||
<DE.Label
|
||||
:label-for="fieldName"
|
||||
:class="cn('select-field-label', labelClass)"
|
||||
:is-required="isRequired"
|
||||
>
|
||||
{{ label }}
|
||||
</Label>
|
||||
<Field
|
||||
</DE.Label>
|
||||
<DE.Field
|
||||
:id="fieldName"
|
||||
:errors="errors"
|
||||
:class="cn('select-field-wrapper')"
|
||||
@@ -150,6 +64,6 @@ const jobOptions = [
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
</FormField>
|
||||
</Field>
|
||||
</FieldGroup>
|
||||
</DE.Field>
|
||||
</DE.Cell>
|
||||
</template>
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
<script setup lang="ts">
|
||||
import type { FormErrors } from '~/types/error'
|
||||
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 { cn } from '~/lib/utils'
|
||||
|
||||
import * as DE from '~/components/pub/my-ui/doc-entry'
|
||||
|
||||
const props = defineProps<{
|
||||
fieldName?: string
|
||||
label?: string
|
||||
@@ -41,15 +40,15 @@ const langOptions = [
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<FieldGroup :class="cn('select-field-group', fieldGroupClass, containerClass)">
|
||||
<Label
|
||||
<DE.Cell :class="cn('select-field-group', fieldGroupClass, containerClass)">
|
||||
<DE.Label
|
||||
:label-for="fieldName"
|
||||
:class="cn('select-field-label', labelClass)"
|
||||
:is-required="isRequired"
|
||||
>
|
||||
{{ label }}
|
||||
</Label>
|
||||
<Field
|
||||
</DE.Label>
|
||||
<DE.Field
|
||||
:id="fieldName"
|
||||
:errors="errors"
|
||||
:class="cn('select-field-wrapper')"
|
||||
@@ -77,6 +76,6 @@ const langOptions = [
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
</FormField>
|
||||
</Field>
|
||||
</FieldGroup>
|
||||
</DE.Field>
|
||||
</DE.Cell>
|
||||
</template>
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
<script setup lang="ts">
|
||||
import type { FormErrors } from '~/types/error'
|
||||
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 { cn } from '~/lib/utils'
|
||||
|
||||
import * as DE from '~/components/pub/my-ui/doc-entry'
|
||||
|
||||
const props = defineProps<{
|
||||
fieldName?: string
|
||||
label?: string
|
||||
@@ -37,15 +36,15 @@ const maritalStatusOptions = [
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<FieldGroup :class="cn('select-field-group', fieldGroupClass, containerClass)">
|
||||
<Label
|
||||
<DE.Cell :class="cn('select-field-group', fieldGroupClass, containerClass)">
|
||||
<DE.Label
|
||||
:label-for="fieldName"
|
||||
:class="cn('select-field-label', labelClass)"
|
||||
:is-required="isRequired"
|
||||
>
|
||||
{{ label }}
|
||||
</Label>
|
||||
<Field
|
||||
</DE.Label>
|
||||
<DE.Field
|
||||
:id="fieldName"
|
||||
:errors="errors"
|
||||
:class="cn('select-field-wrapper')"
|
||||
@@ -73,6 +72,6 @@ const maritalStatusOptions = [
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
</FormField>
|
||||
</Field>
|
||||
</FieldGroup>
|
||||
</DE.Field>
|
||||
</DE.Cell>
|
||||
</template>
|
||||
|
||||
@@ -1,12 +1,11 @@
|
||||
<script setup lang="ts">
|
||||
import type { FormErrors } from '~/types/error'
|
||||
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 { religionCodes } from '~/lib/constants'
|
||||
import { cn, mapToComboboxOptList } from '~/lib/utils'
|
||||
|
||||
import * as DE from '~/components/pub/my-ui/doc-entry'
|
||||
|
||||
const props = defineProps<{
|
||||
fieldName?: string
|
||||
label?: string
|
||||
@@ -45,15 +44,15 @@ const religionOptions = [
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<FieldGroup :class="cn('select-field-group', fieldGroupClass, containerClass)">
|
||||
<Label
|
||||
<DE.Cell :class="cn('select-field-group', fieldGroupClass, containerClass)">
|
||||
<DE.Label
|
||||
:label-for="fieldName"
|
||||
:class="cn('select-field-label', labelClass)"
|
||||
:is-required="isRequired"
|
||||
>
|
||||
{{ label }}
|
||||
</Label>
|
||||
<Field
|
||||
</DE.Label>
|
||||
<DE.Field
|
||||
:id="fieldName"
|
||||
:errors="errors"
|
||||
:class="cn('select-field-wrapper')"
|
||||
@@ -81,6 +80,6 @@ const religionOptions = [
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
</FormField>
|
||||
</Field>
|
||||
</FieldGroup>
|
||||
</DE.Field>
|
||||
</DE.Cell>
|
||||
</template>
|
||||
|
||||
@@ -3,12 +3,14 @@ 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 InputFile from './_common/input-file.vue'
|
||||
import InputPatientName from './_common/input-patient-name.vue'
|
||||
import FileUpload from '~/components/pub/my-ui/form/file-field.vue'
|
||||
import InputName from './_common/input-name.vue'
|
||||
import RadioCommunicationBarrier from './_common/radio-communication-barrier.vue'
|
||||
import RadioDisability from './_common/radio-disability.vue'
|
||||
import RadioGender from './_common/radio-gender.vue'
|
||||
import SelectGender from './_common/select-gender.vue'
|
||||
import RadioNationality from './_common/radio-nationality.vue'
|
||||
import RadioNewborn from './_common/radio-newborn.vue'
|
||||
import SelectBirthPlace from '~/components/app/person/_common/select-birth-place.vue'
|
||||
import SelectDisability from './_common/select-disability.vue'
|
||||
import SelectDob from './_common/select-dob.vue'
|
||||
import SelectEducation from './_common/select-education.vue'
|
||||
@@ -17,6 +19,9 @@ import SelectJob from './_common/select-job.vue'
|
||||
import SelectLanguage from './_common/select-lang.vue'
|
||||
import SelectMaritalStatus from './_common/select-marital-status.vue'
|
||||
import SelectReligion from './_common/select-religion.vue'
|
||||
import Separator from '~/components/pub/ui/separator/Separator.vue'
|
||||
|
||||
import * as DE from '~/components/pub/my-ui/doc-entry'
|
||||
|
||||
const props = defineProps<{
|
||||
schema: any
|
||||
@@ -46,180 +51,161 @@ defineExpose({
|
||||
validation-mode="onSubmit"
|
||||
:initial-values="initialValues ? initialValues : {}"
|
||||
>
|
||||
<div class="mb-3 border-b border-b-slate-300">
|
||||
<p class="text-md mt-1 font-semibold">Data Diri Pasien</p>
|
||||
<div class="grid grid-cols-1 md:grid-cols-[150px_1fr]">
|
||||
<InputPatientName
|
||||
field-name-alias="alias"
|
||||
field-name-input="fullName"
|
||||
label-for-alias="Alias"
|
||||
label-for-input="Nama Lengkap"
|
||||
placeholder="Masukkan nama lengkap pasien"
|
||||
:errors="errors"
|
||||
is-required
|
||||
/>
|
||||
</div>
|
||||
<div class="grid grid-cols-1 md:grid-cols-3">
|
||||
<InputBase
|
||||
field-name="birthPlace"
|
||||
label="Tempat Lahir"
|
||||
placeholder="Malang"
|
||||
:errors="errors"
|
||||
is-required
|
||||
/>
|
||||
<SelectDob
|
||||
label="Tanggal Lahir"
|
||||
:errors="errors"
|
||||
is-required
|
||||
/>
|
||||
</div>
|
||||
<div class="grid grid-cols-1 sm:grid-cols-2 md:grid-cols-3">
|
||||
<RadioGender
|
||||
field-name="gender"
|
||||
label="Jenis Kelamin"
|
||||
placeholder="Pilih jenis kelamin"
|
||||
:errors="errors"
|
||||
is-required
|
||||
/>
|
||||
<RadioNationality
|
||||
field-name="nationality"
|
||||
label="Kebangsaan"
|
||||
placeholder="Pilih kebangsaan"
|
||||
:errors="errors"
|
||||
is-required
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<p class="text-sm 2xl:text-base mb-2 2xl:mb-3 font-semibold">Data Diri Pasien</p>
|
||||
<DE.Block :col-count="4" :cell-flex="false">
|
||||
<InputBase
|
||||
field-name="identityNumber"
|
||||
label="No. KTP"
|
||||
placeholder="Masukkan NIK"
|
||||
:errors="errors"
|
||||
numeric-only
|
||||
/>
|
||||
<InputBase
|
||||
field-name="drivingLicenseNumber"
|
||||
label="No. SIM"
|
||||
placeholder="Masukkan nomor SIM"
|
||||
numeric-only
|
||||
:max-length="20"
|
||||
:errors="errors"
|
||||
/>
|
||||
<InputBase
|
||||
field-name="passportNumber"
|
||||
label="No. Paspor"
|
||||
placeholder="Masukkan nomor paspor"
|
||||
:max-length="20"
|
||||
:errors="errors"
|
||||
/>
|
||||
<InputName
|
||||
field-name-alias="alias"
|
||||
field-name-input="fullName"
|
||||
label-for-input="Nama Lengkap"
|
||||
placeholder="Masukkan nama lengkap pasien"
|
||||
:errors="errors"
|
||||
is-required
|
||||
/>
|
||||
<RadioNewborn
|
||||
field-name="isNewBorn"
|
||||
label="Pasien Bayi"
|
||||
placeholder="Pilih status pasien"
|
||||
:errors="errors"
|
||||
is-required
|
||||
/>
|
||||
<SelectGender
|
||||
field-name="gender"
|
||||
label="Jenis Kelamin"
|
||||
placeholder="Pilih jenis kelamin"
|
||||
:errors="errors"
|
||||
is-required
|
||||
/>
|
||||
<SelectBirthPlace
|
||||
field-name="birthPlace"
|
||||
label="Tempat Lahir"
|
||||
placeholder="Pilih tempat lahir"
|
||||
:errors="errors"
|
||||
is-required
|
||||
/>
|
||||
<SelectDob
|
||||
label="Tanggal Lahir"
|
||||
:errors="errors"
|
||||
is-required
|
||||
/>
|
||||
<SelectEducation
|
||||
field-name="education"
|
||||
label="Pendidikan"
|
||||
placeholder="Pilih pendidikan"
|
||||
:errors="errors"
|
||||
is-required
|
||||
/>
|
||||
<SelectJob
|
||||
field-name="job"
|
||||
label="Pekerjaan"
|
||||
placeholder="Pilih pekerjaan"
|
||||
:errors="errors"
|
||||
is-required
|
||||
/>
|
||||
<SelectMaritalStatus
|
||||
field-name="maritalStatus"
|
||||
label="Status Perkawinan"
|
||||
placeholder="Pilih status Perkawinan"
|
||||
:errors="errors"
|
||||
is-required
|
||||
/>
|
||||
<DE.Cell />
|
||||
<RadioNationality
|
||||
field-name="nationality"
|
||||
label="Kebangsaan"
|
||||
placeholder="Pilih kebangsaan"
|
||||
:errors="errors"
|
||||
is-required
|
||||
/>
|
||||
<SelectEthnicity
|
||||
field-name="ethnicity"
|
||||
label="Suku"
|
||||
placeholder="Pilih suku bangsa"
|
||||
:errors="errors"
|
||||
:is-disabled="values.nationality !== 'WNI'"
|
||||
/>
|
||||
<SelectLanguage
|
||||
field-name="language"
|
||||
label="Bahasa"
|
||||
placeholder="Pilih preferensi bahasa"
|
||||
:errors="errors"
|
||||
is-required
|
||||
/>
|
||||
<SelectReligion
|
||||
field-name="religion"
|
||||
label="Agama"
|
||||
placeholder="Pilih agama"
|
||||
:errors="errors"
|
||||
is-required
|
||||
/>
|
||||
<RadioCommunicationBarrier
|
||||
field-name="communicationBarrier"
|
||||
label="Hambatan Berkomunikasi"
|
||||
:errors="errors"
|
||||
is-required
|
||||
/>
|
||||
<RadioDisability
|
||||
field-name="disability"
|
||||
label="Disabilitas"
|
||||
:errors="errors"
|
||||
is-required
|
||||
/>
|
||||
<SelectDisability
|
||||
label="Jenis Disabilitas"
|
||||
field-name="disabilityType"
|
||||
:errors="errors"
|
||||
:is-disabled="values.disability !== 'YA'"
|
||||
:is-required="values.disability === 'YA'"
|
||||
/>
|
||||
<InputBase
|
||||
field-name="note"
|
||||
label="Kepercayaan"
|
||||
placeholder="Contoh: tidak ingin diperiksa oleh dokter laki-laki"
|
||||
:errors="errors"
|
||||
/>
|
||||
</DE.Block>
|
||||
|
||||
<div class="mb-3 border-b border-b-slate-300">
|
||||
<p class="text-md mt-1 font-semibold">Dokumen Identitas</p>
|
||||
<div class="h-6"></div>
|
||||
|
||||
<div class="grid grid-cols-1 md:grid-cols-3">
|
||||
<InputBase
|
||||
field-name="identityNumber"
|
||||
label="No. KTP"
|
||||
placeholder="Masukkan NIK"
|
||||
:errors="errors"
|
||||
numeric-only
|
||||
:max-length="16"
|
||||
is-required
|
||||
/>
|
||||
<InputBase
|
||||
field-name="drivingLicenseNumber"
|
||||
label="No. SIM"
|
||||
placeholder="Masukkan nomor SIM"
|
||||
numeric-only
|
||||
:max-length="20"
|
||||
:errors="errors"
|
||||
/>
|
||||
|
||||
<InputBase
|
||||
field-name="passportNumber"
|
||||
label="No. Paspor"
|
||||
placeholder="Masukkan nomor paspor"
|
||||
:max-length="20"
|
||||
:errors="errors"
|
||||
/>
|
||||
</div>
|
||||
<div class="grid grid-cols-1 md:grid-cols-2">
|
||||
<InputFile
|
||||
field-name="identityCardFile"
|
||||
label="Dokumen KTP"
|
||||
placeholder="Unggah scan dokumen KTP"
|
||||
:errors="errors"
|
||||
/>
|
||||
<InputFile
|
||||
field-name="familyCardFile"
|
||||
label="Dokumen KK"
|
||||
placeholder="Unggah scan dokumen KK"
|
||||
:errors="errors"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mb-3 border-b border-b-slate-300">
|
||||
<p class="text-md mt-1 font-semibold">Data Demografis</p>
|
||||
|
||||
<div class="grid grid-cols-1 md:grid-cols-3">
|
||||
<SelectReligion
|
||||
field-name="religion"
|
||||
label="Agama"
|
||||
placeholder="Pilih agama"
|
||||
:errors="errors"
|
||||
is-required
|
||||
/>
|
||||
<SelectEthnicity
|
||||
field-name="ethnicity"
|
||||
label="Suku"
|
||||
placeholder="Pilih suku bangsa"
|
||||
:errors="errors"
|
||||
:is-disabled="values.nationality !== 'WNI'"
|
||||
/>
|
||||
<SelectLanguage
|
||||
field-name="language"
|
||||
label="Bahasa"
|
||||
placeholder="Pilih preferensi bahasa"
|
||||
:errors="errors"
|
||||
is-required
|
||||
/>
|
||||
</div>
|
||||
<div class="grid grid-cols-1 md:grid-cols-3">
|
||||
<SelectMaritalStatus
|
||||
field-name="maritalStatus"
|
||||
label="Status Perkawinan"
|
||||
placeholder="Pilih status Perkawinan"
|
||||
:errors="errors"
|
||||
is-required
|
||||
/>
|
||||
<SelectEducation
|
||||
field-name="education"
|
||||
label="Pendidikan"
|
||||
placeholder="Pilih pendidikan"
|
||||
:errors="errors"
|
||||
is-required
|
||||
/>
|
||||
<SelectJob
|
||||
field-name="job"
|
||||
label="Pekerjaan"
|
||||
placeholder="Pilih pekerjaan"
|
||||
:errors="errors"
|
||||
is-required
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mb-3 border-b border-b-slate-300">
|
||||
<p class="text-md mt-1 font-semibold">Kondisi Khusus</p>
|
||||
<div class="grid grid-cols-1 md:grid-cols-3">
|
||||
<RadioCommunicationBarrier
|
||||
field-name="communicationBarrier"
|
||||
label="Hambatan Berkomunikasi"
|
||||
:errors="errors"
|
||||
is-required
|
||||
/>
|
||||
<div class="cols-span-1">
|
||||
<RadioDisability
|
||||
field-name="disability"
|
||||
label="Disabilitas"
|
||||
:errors="errors"
|
||||
is-required
|
||||
/>
|
||||
<SelectDisability
|
||||
label="Jenis Disabilitas"
|
||||
field-name="disabilityType"
|
||||
:errors="errors"
|
||||
:is-disabled="values.disability !== 'YA'"
|
||||
:is-required="values.disability === 'YA'"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<InputBase
|
||||
field-name="note"
|
||||
label="Kepercayaan"
|
||||
placeholder="Contoh: tidak ingin diperiksa oleh dokter laki-laki"
|
||||
:errors="errors"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<p class="text-sm 2xl:text-base mb-2 2xl:mb-3 font-semibold">Dokumen Identitas</p>
|
||||
<DE.Block :col-count="2" :cell-flex="false">
|
||||
<FileUpload
|
||||
field-name="identityCardFile"
|
||||
label="Dokumen KTP"
|
||||
placeholder="Unggah scan dokumen KTP"
|
||||
:errors="errors"
|
||||
:accept="['pdf', 'jpg', 'png']"
|
||||
:max-size-mb="1"
|
||||
/>
|
||||
<FileUpload
|
||||
field-name="familyCardFile"
|
||||
label="Dokumen KK"
|
||||
placeholder="Unggah scan dokumen KK"
|
||||
:errors="errors"
|
||||
:accept="['pdf', 'jpg', 'png']"
|
||||
:max-size-mb="1"
|
||||
/>
|
||||
</DE.Block>
|
||||
</Form>
|
||||
</template>
|
||||
|
||||
@@ -1,100 +1,100 @@
|
||||
import type {
|
||||
Col,
|
||||
KeyLabel,
|
||||
RecComponent,
|
||||
RecStrFuncComponent,
|
||||
RecStrFuncUnknown,
|
||||
Th,
|
||||
} from '~/components/pub/my-ui/data/types'
|
||||
import type { PatientEntity } from '~/models/patient'
|
||||
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-dud.vue'))
|
||||
|
||||
export const cols: Col[] = [{}, {}, {}, {}, {}, {}, {}, { width: 5 }]
|
||||
export const config: Config = {
|
||||
cols: [{}, {}, {}, {}, {}, {}, {}, { width: 5 }],
|
||||
|
||||
export const header: Th[][] = [
|
||||
[
|
||||
{ label: 'Nama' },
|
||||
{ label: 'NIK' },
|
||||
{ label: 'Tgl Lahir' },
|
||||
{ label: 'Umur' },
|
||||
{ label: 'Jenis Kelamin' },
|
||||
{ label: 'Pendidikan' },
|
||||
{ label: '' },
|
||||
headers: [
|
||||
[
|
||||
{ label: 'ID' },
|
||||
{ label: 'Nama' },
|
||||
{ label: 'NIK/No. Paspor' },
|
||||
{ label: 'Tgl Lahir' },
|
||||
{ label: 'Umur' },
|
||||
{ label: 'Jenis Kelamin' },
|
||||
{ label: 'Pendidikan' },
|
||||
{ label: '' },
|
||||
],
|
||||
],
|
||||
]
|
||||
|
||||
export const keys = ['name', 'identity_number', 'birth_date', 'patient_age', 'gender', 'education', 'action']
|
||||
keys: ['patientId', 'name', 'identity_number', 'birth_date', 'patient_age', 'gender', 'education', 'action'],
|
||||
|
||||
export const delKeyNames: KeyLabel[] = [
|
||||
{ key: 'code', label: 'Kode' },
|
||||
{ key: 'name', label: 'Nama' },
|
||||
]
|
||||
delKeyNames: [
|
||||
{ key: 'code', label: 'Kode' },
|
||||
{ key: 'name', label: 'Nama' },
|
||||
],
|
||||
|
||||
export const funcParsed: RecStrFuncUnknown = {
|
||||
name: (rec: unknown): unknown => {
|
||||
const { person } = rec as PatientEntity
|
||||
return person.name.trim()
|
||||
parses: {
|
||||
patientId: (rec: unknown): unknown => {
|
||||
const patient = rec as Patient
|
||||
return patient.number
|
||||
},
|
||||
name: (rec: unknown): unknown => {
|
||||
const { person } = rec as Patient
|
||||
return person.name.trim()
|
||||
},
|
||||
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 '-'
|
||||
},
|
||||
},
|
||||
identity_number: (rec: unknown): unknown => {
|
||||
const { person } = rec as PatientEntity
|
||||
|
||||
if (person?.residentIdentityNumber?.substring(0, 5) === 'BLANK') {
|
||||
return '(TANPA NIK)'
|
||||
}
|
||||
return person.residentIdentityNumber
|
||||
components: {
|
||||
action(rec, idx) {
|
||||
return {
|
||||
idx,
|
||||
rec: rec as object,
|
||||
component: action,
|
||||
}
|
||||
},
|
||||
},
|
||||
birth_date: (rec: unknown): unknown => {
|
||||
const { person } = rec as PatientEntity
|
||||
|
||||
if (typeof person.birthDate == 'object' && person.birthDate) {
|
||||
return (person.birthDate as Date).toLocaleDateString()
|
||||
} 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 PatientEntity
|
||||
return calculateAge(person.birthDate)
|
||||
},
|
||||
gender: (rec: unknown): unknown => {
|
||||
const { person } = rec as PatientEntity
|
||||
|
||||
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 PatientEntity
|
||||
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 '-'
|
||||
},
|
||||
}
|
||||
|
||||
export const funcComponent: RecStrFuncComponent = {
|
||||
action(rec, idx) {
|
||||
const res: RecComponent = {
|
||||
idx,
|
||||
rec: rec as object,
|
||||
component: action,
|
||||
}
|
||||
return res
|
||||
},
|
||||
}
|
||||
|
||||
export const funcHtml: RecStrFuncUnknown = {
|
||||
patient_address(_rec) {
|
||||
return '-'
|
||||
htmls: {
|
||||
patient_address(_rec) {
|
||||
return '-'
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
@@ -0,0 +1,96 @@
|
||||
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-dud.vue'))
|
||||
|
||||
export const config: Config = {
|
||||
cols: [{}, {}, {}, {}, {}, {}, {}, { width: 5 }],
|
||||
|
||||
headers: [
|
||||
[
|
||||
{ label: 'No. RM' },
|
||||
{ label: 'Nama' },
|
||||
{ label: 'No. KTP/SIM/Passpor' },
|
||||
{ label: 'Tgl Lahir' },
|
||||
{ label: 'Umur' },
|
||||
{ label: 'Kelamin' },
|
||||
{ label: 'Pendidikan' },
|
||||
{ label: '' },
|
||||
],
|
||||
],
|
||||
|
||||
keys: ['number', 'person.name', 'identity_number', 'birth_date', 'patient_age', 'gender', 'education', '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,
|
||||
}
|
||||
},
|
||||
},
|
||||
|
||||
htmls: {
|
||||
patient_address(_rec) {
|
||||
return '-'
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
<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 { cols, funcComponent, funcHtml, funcParsed, header, keys } from './list-cfg'
|
||||
import { config } from './list.cfg'
|
||||
|
||||
interface Props {
|
||||
data: any[]
|
||||
@@ -22,13 +22,8 @@ function handlePageChange(page: number) {
|
||||
<template>
|
||||
<div class="space-y-4">
|
||||
<PubMyUiDataTable
|
||||
v-bind="config"
|
||||
:rows="data"
|
||||
:cols="cols"
|
||||
:header="header"
|
||||
:keys="keys"
|
||||
:func-parsed="funcParsed"
|
||||
:func-html="funcHtml"
|
||||
:func-component="funcComponent"
|
||||
:skeleton-size="paginationMeta?.pageSize"
|
||||
/>
|
||||
<PaginationView :pagination-meta="paginationMeta" @page-change="handlePageChange" />
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<script setup lang="ts">
|
||||
import { cols, funcComponent, funcHtml, funcParsed, header, keys } from './list-cfg'
|
||||
import { config } from './list.cfg'
|
||||
|
||||
defineProps<{ data: any[] }>()
|
||||
const modelValue = defineModel<any | null>()
|
||||
@@ -8,13 +8,8 @@ const modelValue = defineModel<any | null>()
|
||||
<template>
|
||||
<PubMyUiDataTable
|
||||
v-model="modelValue"
|
||||
v-bind="config"
|
||||
select-mode="single"
|
||||
:rows="data"
|
||||
:cols="cols"
|
||||
:header="header"
|
||||
:keys="keys"
|
||||
:func-parsed="funcParsed"
|
||||
:func-html="funcHtml"
|
||||
:func-component="funcComponent"
|
||||
/>
|
||||
</template>
|
||||
|
||||
@@ -1,21 +1,23 @@
|
||||
<script setup lang="ts">
|
||||
import type { Person } from '~/models/person'
|
||||
import type { PersonAddress } from '~/models/person-address'
|
||||
import type { PersonContact } from '~/models/person-contact'
|
||||
import type { PersonRelative } from '~/models/person-relative'
|
||||
|
||||
import type { Patient } from '~/models/patient'
|
||||
import DetailRow from '~/components/pub/my-ui/form/view/detail-row.vue'
|
||||
import DetailSection from '~/components/pub/my-ui/form/view/detail-section.vue'
|
||||
import { formatAddress } from '~/models/person-address'
|
||||
|
||||
import { educationCodes, genderCodes, personContactTypes, relationshipCodes, religionCodes } from '~/lib/constants'
|
||||
import {
|
||||
addressLocationTypeCode,
|
||||
educationCodes,
|
||||
genderCodes,
|
||||
occupationCodes,
|
||||
personContactTypes,
|
||||
relationshipCodes,
|
||||
religionCodes,
|
||||
} from '~/lib/constants'
|
||||
import { mapToComboboxOptList } from '~/lib/utils'
|
||||
|
||||
// #region Props & Emits
|
||||
const props = defineProps<{
|
||||
person: Person
|
||||
personAddresses: PersonAddress[]
|
||||
personContacts: PersonContact[]
|
||||
personRelatives: PersonRelative[]
|
||||
patient: Patient
|
||||
}>()
|
||||
|
||||
const emit = defineEmits<{
|
||||
@@ -28,17 +30,28 @@ const emit = defineEmits<{
|
||||
const genderOptions = mapToComboboxOptList(genderCodes)
|
||||
const religionOptions = mapToComboboxOptList(religionCodes)
|
||||
const educationOptions = mapToComboboxOptList(educationCodes)
|
||||
const occupationOptions = mapToComboboxOptList(occupationCodes)
|
||||
const relationshipOptions = mapToComboboxOptList(relationshipCodes)
|
||||
const personContactTypeOptions = mapToComboboxOptList(personContactTypes)
|
||||
|
||||
const residentAddress = 'Jl. Puncak Borobudur Blok M No. 321, Lowokwaru, Kota Malang, Jawa Timur'
|
||||
const primaryAddress = 'Perumahan Araya Cluster B, No 22, Blimbing, Kota Malang, Jawa Timur'
|
||||
// Computed addresses from nested data
|
||||
const domicileAddress = computed(() => {
|
||||
const addresses = props.patient.person.addresses
|
||||
const resident = addresses?.find((addr) => addr.locationType_code === 'domicile')
|
||||
return formatAddress(resident)
|
||||
})
|
||||
|
||||
const identityAddress = computed(() => {
|
||||
const addresses = props.patient.person.addresses
|
||||
const primary = addresses?.find((addr) => addr.locationType_code === 'identity')
|
||||
return formatAddress(primary)
|
||||
})
|
||||
|
||||
const patientAge = computed(() => {
|
||||
if (!props.person.birthDate) {
|
||||
if (!props.patient.person.birthDate) {
|
||||
return '-'
|
||||
}
|
||||
const birthDate = new Date(props.person.birthDate)
|
||||
const birthDate = new Date(props.patient.person.birthDate)
|
||||
const today = new Date()
|
||||
let age = today.getFullYear() - birthDate.getFullYear()
|
||||
const monthDiff = today.getMonth() - birthDate.getMonth()
|
||||
@@ -53,6 +66,7 @@ const patientAge = computed(() => {
|
||||
// #endregion
|
||||
|
||||
// #region Functions
|
||||
|
||||
// #endregion region
|
||||
|
||||
// #region Utilities & event handlers
|
||||
@@ -67,48 +81,53 @@ function onClick(type: string) {
|
||||
|
||||
<template>
|
||||
<DetailSection title="Data Pasien">
|
||||
<DetailRow label="Nomor ID">{{ person.id || '-' }}</DetailRow>
|
||||
<DetailRow label="Sapaan">{{ person.alias || '-' }}</DetailRow>
|
||||
<DetailRow label="Nama Lengkap">{{ person.name || '-' }}</DetailRow>
|
||||
<DetailRow label="Nomor">{{ patient.number || '-' }}</DetailRow>
|
||||
<DetailRow label="Nama Lengkap">{{ patient.person.name || '-' }}</DetailRow>
|
||||
<DetailRow label="Tempat, tanggal lahir">
|
||||
{{ person.birthRegency_code || '-' }},
|
||||
{{ person.birthDate ? new Date(person.birthDate).toLocaleDateString() : '-' }}
|
||||
{{ patient.person.birthRegency?.name || '-' }},
|
||||
{{ patient.person.birthDate ? new Date(patient.person.birthDate).toLocaleDateString('id-ID') : '-' }}
|
||||
</DetailRow>
|
||||
<DetailRow label="Usia">{{ patientAge || '-' }}</DetailRow>
|
||||
<DetailRow label="Usia">{{ patientAge || '-' }} Tahun</DetailRow>
|
||||
<DetailRow label="Tanggal Daftar">
|
||||
{{ person.createdAt ? new Date(person.createdAt).toLocaleDateString() : '-' }}
|
||||
{{ patient.person.createdAt ? new Date(patient.person.createdAt).toLocaleDateString('id-ID') : '-' }}
|
||||
</DetailRow>
|
||||
<DetailRow label="Jenis Kelamin">
|
||||
{{ genderOptions.find((item) => item.code === person.gender_code)?.label || '-' }}
|
||||
{{ genderOptions.find((item) => item.code === patient.person.gender_code)?.label || '-' }}
|
||||
</DetailRow>
|
||||
|
||||
<DetailRow label="NIK">{{ person.residentIdentityNumber || '-' }}</DetailRow>
|
||||
<DetailRow label="No. SIM">{{ person.drivingLicenseNumber || '-' }}</DetailRow>
|
||||
<DetailRow label="No. Paspor">{{ person.passportNumber || '-' }}</DetailRow>
|
||||
<DetailRow label="NIK">{{ patient.person.residentIdentityNumber || '-' }}</DetailRow>
|
||||
<DetailRow label="No. SIM">{{ patient.person.drivingLicenseNumber || '-' }}</DetailRow>
|
||||
<DetailRow label="No. Paspor">{{ patient.person.passportNumber || '-' }}</DetailRow>
|
||||
|
||||
<DetailRow label="Agama">
|
||||
{{ religionOptions.find((item) => item.code === person.religion_code)?.label || '-' }}
|
||||
{{ religionOptions.find((item) => item.code === patient.person.religion_code)?.label || '-' }}
|
||||
</DetailRow>
|
||||
<DetailRow label="Suku">{{ person.ethnic_code || '-' }}</DetailRow>
|
||||
<DetailRow label="Bahasa">{{ person.language_code || '-' }}</DetailRow>
|
||||
<DetailRow label="Suku">{{ patient.person.ethnic?.name || '-' }}</DetailRow>
|
||||
<DetailRow label="Bahasa">{{ patient.person.language?.name || '-' }}</DetailRow>
|
||||
<DetailRow label="Pendidikan">
|
||||
{{ educationOptions.find((item) => item.code === person.education_code)?.label || '-' }}
|
||||
{{ educationOptions.find((item) => item.code === patient.person.education_code)?.label || '-' }}
|
||||
</DetailRow>
|
||||
<DetailRow label="Pekerjaan">
|
||||
{{
|
||||
occupationOptions.find((item) => item.code === patient.person.occupation_code)?.label ||
|
||||
patient.person.occupation_name ||
|
||||
'-'
|
||||
}}
|
||||
</DetailRow>
|
||||
<DetailRow label="Pekerjaan">{{ person.occupation_name || '-' }}</DetailRow>
|
||||
</DetailSection>
|
||||
|
||||
<DetailSection title="Alamat">
|
||||
<DetailRow label="Alamat Domisili">{{ residentAddress || '-' }}</DetailRow>
|
||||
<DetailRow label="Alamat KTP">{{ primaryAddress || '-' }}</DetailRow>
|
||||
<DetailRow :label="addressLocationTypeCode.domicile || 'Alamat Domisili'">{{ domicileAddress || '-' }}</DetailRow>
|
||||
<DetailRow :label="addressLocationTypeCode.identity || 'Alamat KTP'">{{ identityAddress || '-' }}</DetailRow>
|
||||
</DetailSection>
|
||||
<DetailSection title="Kontak">
|
||||
<template v-if="personContacts && personContacts.length > 0">
|
||||
<template v-if="patient.person.contacts && patient.person.contacts.length > 0">
|
||||
<template
|
||||
v-for="contactType in personContactTypeOptions"
|
||||
:key="contactType.code"
|
||||
>
|
||||
<DetailRow :label="contactType.label">
|
||||
{{ personContacts.find((item) => item.type_code === contactType.code)?.value || '-' }}
|
||||
{{ patient.person.contacts.find((item) => item.type_code === contactType.code)?.value || '-' }}
|
||||
</DetailRow>
|
||||
</template>
|
||||
</template>
|
||||
@@ -116,10 +135,10 @@ function onClick(type: string) {
|
||||
<DetailRow label="Kontak">-</DetailRow>
|
||||
</template>
|
||||
</DetailSection>
|
||||
<DetailSection title="Penanggung Jawab">
|
||||
<template v-if="personRelatives && personRelatives.filter((rel) => rel.responsible).length > 0">
|
||||
<DetailSection title="Orang Tua">
|
||||
<template v-if="patient.person.relatives && patient.person.relatives.filter((rel) => !rel.responsible).length > 0">
|
||||
<template
|
||||
v-for="(relative, index) in personRelatives.filter((rel) => rel.responsible)"
|
||||
v-for="(relative, index) in patient.person.relatives.filter((rel) => !rel.responsible)"
|
||||
:key="relative.id"
|
||||
>
|
||||
<div
|
||||
@@ -130,13 +149,41 @@ function onClick(type: string) {
|
||||
<DetailRow label="Hubungan">
|
||||
{{ relationshipOptions.find((item) => item.code === relative.relationship_code)?.label || '-' }}
|
||||
</DetailRow>
|
||||
<DetailRow label="Jenis Kelamin">
|
||||
<!-- <DetailRow label="Jenis Kelamin">
|
||||
{{ genderOptions.find((item) => item.code === relative.gender_code)?.label || '-' }}
|
||||
</DetailRow>
|
||||
</DetailRow> -->
|
||||
<DetailRow label="Pendidikan">
|
||||
{{ educationOptions.find((item) => item.code === relative.education_code)?.label || '-' }}
|
||||
</DetailRow>
|
||||
<DetailRow label="Pekerjaan">{{ relative.occupation_name || '-' }}</DetailRow>
|
||||
<DetailRow label="Pekerjaan">
|
||||
{{
|
||||
occupationOptions.find((item) => item.code === relative.occupation_code)?.label ||
|
||||
relative.occupation_name ||
|
||||
'-'
|
||||
}}
|
||||
</DetailRow>
|
||||
<!-- <DetailRow label="Alamat">{{ relative.address || '-' }}</DetailRow> -->
|
||||
<!-- <DetailRow label="Nomor HP">{{ relative.phoneNumber || '-' }}</DetailRow> -->
|
||||
</template>
|
||||
</template>
|
||||
<template v-else>
|
||||
<DetailRow label="Orang Tua">-</DetailRow>
|
||||
</template>
|
||||
</DetailSection>
|
||||
<DetailSection title="Penanggung Jawab">
|
||||
<template v-if="patient.person.relatives && patient.person.relatives.filter((rel) => rel.responsible).length > 0">
|
||||
<template
|
||||
v-for="(relative, index) in patient.person.relatives.filter((rel) => rel.responsible)"
|
||||
:key="relative.id"
|
||||
>
|
||||
<div
|
||||
v-if="index > 0"
|
||||
class="mt-3 border-t border-gray-200 pt-3"
|
||||
></div>
|
||||
<DetailRow label="Nama">{{ relative.name || '-' }}</DetailRow>
|
||||
<DetailRow label="Hubungan">
|
||||
{{ relationshipOptions.find((item) => item.code === relative.relationship_code)?.label || '-' }}
|
||||
</DetailRow>
|
||||
<DetailRow label="Alamat">{{ relative.address || '-' }}</DetailRow>
|
||||
<DetailRow label="Nomor HP">{{ relative.phoneNumber || '-' }}</DetailRow>
|
||||
</template>
|
||||
|
||||
@@ -6,8 +6,11 @@ import Field from '~/components/pub/my-ui/form/field.vue'
|
||||
import Label from '~/components/pub/my-ui/form/label.vue'
|
||||
import { cn } from '~/lib/utils'
|
||||
|
||||
import * as DE from '~/components/pub/my-ui/doc-entry'
|
||||
|
||||
const props = defineProps<{
|
||||
fieldName: string
|
||||
fieldName?: string
|
||||
regencyCode?: string
|
||||
isDisabled?: boolean
|
||||
placeholder?: string
|
||||
errors?: FormErrors
|
||||
@@ -17,24 +20,41 @@ const props = defineProps<{
|
||||
isRequired?: boolean
|
||||
}>()
|
||||
|
||||
const { placeholder = 'Pilih Kecamatan', errors, class: containerClass, selectClass, fieldGroupClass } = props
|
||||
const {
|
||||
fieldName = 'districtId',
|
||||
placeholder = 'Pilih kecamatan',
|
||||
errors,
|
||||
class: containerClass,
|
||||
fieldGroupClass,
|
||||
} = props
|
||||
|
||||
const districtOptions = [
|
||||
{ label: 'Kecamatan Lowokwaru', value: '18' },
|
||||
{ label: 'Kecamatan Pakis', value: '33' },
|
||||
{ label: 'Kecamatan Blimbing', value: '35' },
|
||||
]
|
||||
// Gunakan composable untuk mengelola data districts
|
||||
const regencyCodeRef = toRef(props, 'regencyCode')
|
||||
const { districtOptions, isLoading, error } = useDistricts(regencyCodeRef)
|
||||
|
||||
// Computed untuk menentukan placeholder berdasarkan state
|
||||
const dynamicPlaceholder = computed(() => {
|
||||
if (!props.regencyCode) return 'Pilih kabupaten/kota dahulu'
|
||||
if (isLoading.value) return 'Memuat data kecamatan...'
|
||||
if (error.value) return 'Gagal memuat data'
|
||||
return placeholder
|
||||
})
|
||||
|
||||
// Computed untuk menentukan apakah field disabled
|
||||
const isFieldDisabled = computed(() => {
|
||||
return props.isDisabled || !props.regencyCode || isLoading.value || !!error.value
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<FieldGroup :class="cn('select-field-group', fieldGroupClass, containerClass)">
|
||||
<Label
|
||||
<DE.Cell :class="cn('select-field-group', fieldGroupClass, containerClass)">
|
||||
<DE.Label
|
||||
:label-for="fieldName"
|
||||
:is-required="isRequired"
|
||||
>
|
||||
Kecamatan
|
||||
</Label>
|
||||
<Field
|
||||
</DE.Label>
|
||||
<DE.Field
|
||||
:id="fieldName"
|
||||
:errors="errors"
|
||||
:class="cn('select-field-wrapper')"
|
||||
@@ -49,15 +69,15 @@ const districtOptions = [
|
||||
:id="fieldName"
|
||||
v-bind="componentField"
|
||||
:items="districtOptions"
|
||||
:placeholder="placeholder"
|
||||
:is-disabled="isDisabled"
|
||||
search-placeholder="Cari..."
|
||||
:placeholder="dynamicPlaceholder"
|
||||
:is-disabled="isFieldDisabled"
|
||||
search-placeholder="Cari kecamatan..."
|
||||
empty-message="Kecamatan tidak ditemukan"
|
||||
/>
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
</FormField>
|
||||
</Field>
|
||||
</FieldGroup>
|
||||
</DE.Field>
|
||||
</DE.Cell>
|
||||
</template>
|
||||
|
||||
@@ -6,8 +6,11 @@ import Field from '~/components/pub/my-ui/form/field.vue'
|
||||
import Label from '~/components/pub/my-ui/form/label.vue'
|
||||
import { cn } from '~/lib/utils'
|
||||
|
||||
import * as DE from '~/components/pub/my-ui/doc-entry'
|
||||
|
||||
const props = defineProps<{
|
||||
fieldName: string
|
||||
villageCode?: string
|
||||
isDisabled?: boolean
|
||||
placeholder?: string
|
||||
errors?: FormErrors
|
||||
@@ -17,37 +20,32 @@ const props = defineProps<{
|
||||
isRequired?: boolean
|
||||
}>()
|
||||
|
||||
const {
|
||||
fieldName = 'zipCode',
|
||||
placeholder = 'Kode Pos',
|
||||
errors,
|
||||
class: containerClass,
|
||||
selectClass,
|
||||
fieldGroupClass,
|
||||
} = props
|
||||
const { fieldName = 'postalRegion', placeholder = 'Kode Pos', errors, class: containerClass, fieldGroupClass } = props
|
||||
|
||||
const postalCodeOptions = [
|
||||
{ label: '65120', value: '65120' },
|
||||
{ label: '65121', value: '65121' },
|
||||
{ label: '65123', value: '65123' },
|
||||
{ label: '65124', value: '65124' },
|
||||
{ label: '65125', value: '65125' },
|
||||
{ label: '65126', value: '65126' },
|
||||
{ label: '65127', value: '65127' },
|
||||
{ label: '65128', value: '65128' },
|
||||
{ label: '65129', value: '65129' },
|
||||
]
|
||||
const villageCodeRef = toRef(props, 'villageCode')
|
||||
const { postalRegionOptions, isLoading, error } = usePostalRegion(villageCodeRef)
|
||||
|
||||
const dynamicPlaceholder = computed(() => {
|
||||
if (!props.villageCode) return 'Pilih kelurahan terlebih dahulu'
|
||||
if (isLoading.value) return 'Memuat kode pos...'
|
||||
if (error.value) return 'Gagal memuat data'
|
||||
return placeholder
|
||||
})
|
||||
|
||||
const isFieldDisabled = computed(() => {
|
||||
return props.isDisabled || !props.villageCode || isLoading.value || !!error.value
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<FieldGroup :class="cn('select-field-group', fieldGroupClass, containerClass)">
|
||||
<Label
|
||||
<DE.Cell :class="cn('select-field-group', fieldGroupClass, containerClass)">
|
||||
<DE.Label
|
||||
:label-for="fieldName"
|
||||
:is-required="isRequired"
|
||||
>
|
||||
Kode Pos
|
||||
</Label>
|
||||
<Field
|
||||
</DE.Label>
|
||||
<DE.Field
|
||||
:id="fieldName"
|
||||
:errors="errors"
|
||||
:class="cn('select-field-wrapper')"
|
||||
@@ -61,9 +59,9 @@ const postalCodeOptions = [
|
||||
<Combobox
|
||||
:id="fieldName"
|
||||
v-bind="componentField"
|
||||
:items="postalCodeOptions"
|
||||
:placeholder="placeholder"
|
||||
:is-disabled="isDisabled"
|
||||
:items="postalRegionOptions"
|
||||
:placeholder="dynamicPlaceholder"
|
||||
:is-disabled="isFieldDisabled"
|
||||
search-placeholder="Cari..."
|
||||
empty-message="Kode pos tidak ditemukan"
|
||||
/>
|
||||
@@ -71,6 +69,6 @@ const postalCodeOptions = [
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
</FormField>
|
||||
</Field>
|
||||
</FieldGroup>
|
||||
</DE.Field>
|
||||
</DE.Cell>
|
||||
</template>
|
||||
|
||||
@@ -6,8 +6,10 @@ import Field from '~/components/pub/my-ui/form/field.vue'
|
||||
import Label from '~/components/pub/my-ui/form/label.vue'
|
||||
import { cn } from '~/lib/utils'
|
||||
|
||||
import * as DE from '~/components/pub/my-ui/doc-entry'
|
||||
|
||||
const props = defineProps<{
|
||||
fieldName: string
|
||||
fieldName?: string
|
||||
isDisabled?: boolean
|
||||
placeholder?: string
|
||||
errors?: FormErrors
|
||||
@@ -18,29 +20,38 @@ const props = defineProps<{
|
||||
}>()
|
||||
|
||||
const {
|
||||
fieldName = 'provinceId',
|
||||
fieldName = 'provinceCode',
|
||||
placeholder = 'Pilih provinsi',
|
||||
errors,
|
||||
class: containerClass,
|
||||
fieldGroupClass,
|
||||
} = props
|
||||
|
||||
const provinceList = [
|
||||
{ label: 'Jawa Barat', value: '18' },
|
||||
{ label: 'Jawa Tengah', value: '33' },
|
||||
{ label: 'Jawa Timur', value: '35' },
|
||||
]
|
||||
// Gunakan composable untuk mengelola data provinces
|
||||
const { provinceOptions, isLoading, error } = useProvinces()
|
||||
|
||||
// Computed untuk menentukan placeholder berdasarkan state
|
||||
const dynamicPlaceholder = computed(() => {
|
||||
if (isLoading.value) return 'Memuat data provinsi...'
|
||||
if (error.value) return 'Gagal memuat data'
|
||||
return placeholder
|
||||
})
|
||||
|
||||
// Computed untuk menentukan apakah field disabled
|
||||
const isFieldDisabled = computed(() => {
|
||||
return props.isDisabled || isLoading.value || !!error.value
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<FieldGroup :class="cn('select-field-group', fieldGroupClass, containerClass)">
|
||||
<Label
|
||||
<DE.Cell :class="cn('select-field-group', fieldGroupClass, containerClass)">
|
||||
<DE.Label
|
||||
:label-for="fieldName"
|
||||
:is-required="isRequired"
|
||||
>
|
||||
Provinsi
|
||||
</Label>
|
||||
<Field
|
||||
</DE.Label>
|
||||
<DE.Field
|
||||
:id="fieldName"
|
||||
:errors="errors"
|
||||
:class="cn('select-field-wrapper')"
|
||||
@@ -54,16 +65,16 @@ const provinceList = [
|
||||
<Combobox
|
||||
:id="fieldName"
|
||||
v-bind="componentField"
|
||||
:items="provinceList"
|
||||
:placeholder="placeholder"
|
||||
:is-disabled="isDisabled"
|
||||
search-placeholder="Cari..."
|
||||
empty-message="Kecamatan tidak ditemukan"
|
||||
:items="provinceOptions"
|
||||
:placeholder="dynamicPlaceholder"
|
||||
:is-disabled="isFieldDisabled"
|
||||
search-placeholder="Cari provinsi..."
|
||||
empty-message="Provinsi tidak ditemukan"
|
||||
/>
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
</FormField>
|
||||
</Field>
|
||||
</FieldGroup>
|
||||
</DE.Field>
|
||||
</DE.Cell>
|
||||
</template>
|
||||
|
||||
@@ -6,8 +6,11 @@ import Field from '~/components/pub/my-ui/form/field.vue'
|
||||
import Label from '~/components/pub/my-ui/form/label.vue'
|
||||
import { cn } from '~/lib/utils'
|
||||
|
||||
import * as DE from '~/components/pub/my-ui/doc-entry'
|
||||
|
||||
const props = defineProps<{
|
||||
fieldName: string
|
||||
fieldName?: string
|
||||
provinceCode?: string
|
||||
isDisabled?: boolean
|
||||
placeholder?: string
|
||||
errors?: FormErrors
|
||||
@@ -17,26 +20,41 @@ const props = defineProps<{
|
||||
isRequired?: boolean
|
||||
}>()
|
||||
|
||||
const { placeholder = 'Pilih kabupaten/kota', errors, class: containerClass, selectClass, fieldGroupClass } = props
|
||||
const {
|
||||
fieldName = 'regencyId',
|
||||
placeholder = 'Pilih kabupaten/kota',
|
||||
errors,
|
||||
class: containerClass,
|
||||
fieldGroupClass,
|
||||
} = props
|
||||
|
||||
const regencyOptions = [
|
||||
{ label: 'Kab. Sidoarjo', value: '32' },
|
||||
{ label: 'Kab. Malang', value: '35' },
|
||||
{ label: 'Kab. Mojokerto', value: '31' },
|
||||
{ label: 'Kab. Lamongan', value: '30' },
|
||||
{ label: 'Kota Malang', value: '18' },
|
||||
]
|
||||
// Gunakan composable untuk mengelola data regencies
|
||||
const provinceCodeRef = toRef(props, 'provinceCode')
|
||||
const { regencyOptions, isLoading, error } = useRegencies({ provinceCode: provinceCodeRef, enablePagination: false })
|
||||
|
||||
// Computed untuk menentukan placeholder berdasarkan state
|
||||
const dynamicPlaceholder = computed(() => {
|
||||
if (!props.provinceCode) return 'Pilih provinsi dahulu'
|
||||
if (isLoading.value) return 'Memuat data kabupaten/kota...'
|
||||
if (error.value) return 'Gagal memuat data'
|
||||
return placeholder
|
||||
})
|
||||
|
||||
// Computed untuk menentukan apakah field disabled
|
||||
const isFieldDisabled = computed(() => {
|
||||
return props.isDisabled || !props.provinceCode || isLoading.value || !!error.value
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<FieldGroup :class="cn('select-field-group', fieldGroupClass, containerClass)">
|
||||
<Label
|
||||
<DE.Cell :class="cn('select-field-group', fieldGroupClass, containerClass)">
|
||||
<DE.Label
|
||||
:label-for="fieldName"
|
||||
:is-required="isRequired"
|
||||
>
|
||||
Kabupaten/Kota
|
||||
</Label>
|
||||
<Field
|
||||
</DE.Label>
|
||||
<DE.Field
|
||||
:id="fieldName"
|
||||
:errors="errors"
|
||||
:class="cn('select-field-wrapper')"
|
||||
@@ -51,15 +69,15 @@ const regencyOptions = [
|
||||
:id="fieldName"
|
||||
v-bind="componentField"
|
||||
:items="regencyOptions"
|
||||
:placeholder="placeholder"
|
||||
:is-disabled="isDisabled"
|
||||
search-placeholder="Cari..."
|
||||
:placeholder="dynamicPlaceholder"
|
||||
:is-disabled="isFieldDisabled"
|
||||
search-placeholder="Cari kabupaten/kota..."
|
||||
empty-message="Kabupaten/kota tidak ditemukan"
|
||||
/>
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
</FormField>
|
||||
</Field>
|
||||
</FieldGroup>
|
||||
</DE.Field>
|
||||
</DE.Cell>
|
||||
</template>
|
||||
|
||||
@@ -6,8 +6,11 @@ import Field from '~/components/pub/my-ui/form/field.vue'
|
||||
import Label from '~/components/pub/my-ui/form/label.vue'
|
||||
import { cn } from '~/lib/utils'
|
||||
|
||||
import * as DE from '~/components/pub/my-ui/doc-entry'
|
||||
|
||||
const props = defineProps<{
|
||||
fieldName: string
|
||||
fieldName?: string
|
||||
districtCode?: string
|
||||
isDisabled?: boolean
|
||||
placeholder?: string
|
||||
errors?: FormErrors
|
||||
@@ -17,25 +20,41 @@ const props = defineProps<{
|
||||
isRequired?: boolean
|
||||
}>()
|
||||
|
||||
const { placeholder = 'Pilih Kelurahan', errors, class: containerClass, selectClass, fieldGroupClass } = props
|
||||
const {
|
||||
fieldName = 'villageId',
|
||||
placeholder = 'Pilih kelurahan',
|
||||
errors,
|
||||
class: containerClass,
|
||||
fieldGroupClass,
|
||||
} = props
|
||||
|
||||
const villageOptions = [
|
||||
{ label: 'Lowokwaru', value: '18' },
|
||||
{ label: 'Dinoyo', value: '33' },
|
||||
{ label: 'Blimbing', value: '35' },
|
||||
{ label: 'Sawojajar', value: '36' },
|
||||
]
|
||||
// Gunakan composable untuk mengelola data villages
|
||||
const districtCodeRef = toRef(props, 'districtCode')
|
||||
const { villageOptions, isLoading, error } = useVillages(districtCodeRef)
|
||||
|
||||
// Computed untuk menentukan placeholder berdasarkan state
|
||||
const dynamicPlaceholder = computed(() => {
|
||||
if (!props.districtCode) return 'Pilih kecamatan dahulu'
|
||||
if (isLoading.value) return 'Memuat data kelurahan...'
|
||||
if (error.value) return 'Gagal memuat data'
|
||||
return placeholder
|
||||
})
|
||||
|
||||
// Computed untuk menentukan apakah field disabled
|
||||
const isFieldDisabled = computed(() => {
|
||||
return props.isDisabled || !props.districtCode || isLoading.value || !!error.value
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<FieldGroup :class="cn('select-field-group', fieldGroupClass, containerClass)">
|
||||
<Label
|
||||
<DE.Cell :class="cn('select-field-group', fieldGroupClass, containerClass)">
|
||||
<DE.Label
|
||||
:label-for="fieldName"
|
||||
:is-required="isRequired"
|
||||
>
|
||||
Kelurahan
|
||||
</Label>
|
||||
<Field
|
||||
</DE.Label>
|
||||
<DE.Field
|
||||
:id="fieldName"
|
||||
:errors="errors"
|
||||
:class="cn('select-field-wrapper')"
|
||||
@@ -50,15 +69,15 @@ const villageOptions = [
|
||||
:id="fieldName"
|
||||
v-bind="componentField"
|
||||
:items="villageOptions"
|
||||
:placeholder="placeholder"
|
||||
:is-disabled="isDisabled"
|
||||
search-placeholder="Cari..."
|
||||
:placeholder="dynamicPlaceholder"
|
||||
:is-disabled="isFieldDisabled"
|
||||
search-placeholder="Cari kelurahan..."
|
||||
empty-message="Kelurahan tidak ditemukan"
|
||||
/>
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
</FormField>
|
||||
</Field>
|
||||
</FieldGroup>
|
||||
</DE.Field>
|
||||
</DE.Cell>
|
||||
</template>
|
||||
|
||||
@@ -6,7 +6,8 @@ import FieldGroup from '~/components/pub/my-ui/form/field-group.vue'
|
||||
import Field from '~/components/pub/my-ui/form/field.vue'
|
||||
import InputBase from '~/components/pub/my-ui/form/input-base.vue'
|
||||
import Label from '~/components/pub/my-ui/form/label.vue'
|
||||
import RadioResidence from './_common/radio-residence.vue'
|
||||
import { Label as RadioLabel } from '~/components/pub/ui/label'
|
||||
import { RadioGroup, RadioGroupItem } from '~/components/pub/ui/radio-group'
|
||||
import SelectDistrict from './_common/select-district.vue'
|
||||
import SelectPostal from './_common/select-postal.vue'
|
||||
import SelectProvince from './_common/select-province.vue'
|
||||
@@ -14,6 +15,8 @@ import SelectRegency from './_common/select-regency.vue'
|
||||
import SelectVillage from './_common/select-village.vue'
|
||||
import { Form } from '~/components/pub/ui/form'
|
||||
|
||||
import * as DE from '~/components/pub/my-ui/doc-entry'
|
||||
|
||||
const props = defineProps<{
|
||||
title: string
|
||||
conf?: {
|
||||
@@ -39,18 +42,27 @@ let isResetting = false
|
||||
|
||||
// Field dependency map for placeholder
|
||||
const fieldStates: Record<string, { dependsOn?: string; placeholder: string }> = {
|
||||
regencyId: { dependsOn: 'provinceId', placeholder: 'Pilih provinsi dahulu' },
|
||||
districtId: { dependsOn: 'regencyId', placeholder: 'Pilih kabupaten/kota dahulu' },
|
||||
villageId: { dependsOn: 'districtId', placeholder: 'Pilih kecamatan dahulu' },
|
||||
zipCode: { dependsOn: 'villageId', placeholder: 'Pilih kelurahan dahulu' },
|
||||
regency_code: { dependsOn: 'province_code', placeholder: 'Pilih provinsi dahulu' },
|
||||
district_code: { dependsOn: 'regency_code', placeholder: 'Pilih kabupaten/kota dahulu' },
|
||||
village_code: { dependsOn: 'district_code', placeholder: 'Pilih kecamatan dahulu' },
|
||||
postalRegion_code: { dependsOn: 'village_code', placeholder: 'Pilih kelurahan dahulu' },
|
||||
address: { placeholder: 'Masukkan alamat' },
|
||||
rt: { placeholder: '001' },
|
||||
rw: { placeholder: '002' },
|
||||
}
|
||||
|
||||
// Computed untuk konversi boolean ke string untuk radio group
|
||||
const isSameAddressString = computed(() => {
|
||||
const value = formRef.value?.values?.isSameAddress
|
||||
if (typeof value === 'boolean') {
|
||||
return value ? '1' : '0'
|
||||
}
|
||||
return value || '1'
|
||||
})
|
||||
// #region Function Helper
|
||||
function getFieldState(field: string) {
|
||||
const state = fieldStates[field]
|
||||
const isSame = formRef.value?.values?.isSameAddress === '1'
|
||||
const isSame = formRef.value?.values?.isSameAddress === true || formRef.value?.values?.isSameAddress === '1'
|
||||
|
||||
// Jika alamat sama, semua field kecuali provinsi disabled
|
||||
if (['address', 'rt', 'rw'].includes(field) && isSame) {
|
||||
@@ -63,7 +75,7 @@ function getFieldState(field: string) {
|
||||
const isDisabledByDependency = !dependencyValue
|
||||
|
||||
// Jika isSame, semua field location disabled
|
||||
if (isSame && ['regencyId', 'districtId', 'villageId', 'zipCode'].includes(field)) {
|
||||
if (isSame && ['regency_code', 'district_code', 'village_code', 'postalRegion_code'].includes(field)) {
|
||||
return { placeholder: '-', disabled: true }
|
||||
}
|
||||
|
||||
@@ -73,7 +85,7 @@ function getFieldState(field: string) {
|
||||
}
|
||||
|
||||
// Jika isSame dan field location, disabled
|
||||
if (isSame && ['regencyId', 'districtId', 'villageId', 'zipCode'].includes(field)) {
|
||||
if (isSame && ['regency_code', 'district_code', 'village_code', 'postalRegion_code'].includes(field)) {
|
||||
return { placeholder: '-', disabled: true }
|
||||
}
|
||||
|
||||
@@ -84,9 +96,9 @@ function getFieldState(field: string) {
|
||||
|
||||
// #region watch
|
||||
|
||||
// Watch provinceId changes
|
||||
// Watch province_code changes
|
||||
watch(
|
||||
() => formRef.value?.values?.provinceId,
|
||||
() => formRef.value?.values?.province_code,
|
||||
(newValue, oldValue) => {
|
||||
if (isResetting || !formRef.value || newValue === oldValue) return
|
||||
|
||||
@@ -95,10 +107,10 @@ watch(
|
||||
|
||||
formRef.value.setValues(
|
||||
{
|
||||
regencyId: undefined,
|
||||
districtId: undefined,
|
||||
villageId: undefined,
|
||||
zipCode: undefined,
|
||||
regency_code: undefined,
|
||||
district_code: undefined,
|
||||
village_code: undefined,
|
||||
postalRegion_code: undefined,
|
||||
},
|
||||
false,
|
||||
)
|
||||
@@ -110,9 +122,9 @@ watch(
|
||||
},
|
||||
)
|
||||
|
||||
// Watch regencyId changes
|
||||
// Watch regency_code changes
|
||||
watch(
|
||||
() => formRef.value?.values?.regencyId,
|
||||
() => formRef.value?.values?.regency_code,
|
||||
(newValue, oldValue) => {
|
||||
if (isResetting || !formRef.value || newValue === oldValue) return
|
||||
|
||||
@@ -121,9 +133,9 @@ watch(
|
||||
|
||||
formRef.value.setValues(
|
||||
{
|
||||
districtId: undefined,
|
||||
villageId: undefined,
|
||||
zipCode: undefined,
|
||||
district_code: undefined,
|
||||
village_code: undefined,
|
||||
postalRegion_code: undefined,
|
||||
},
|
||||
false,
|
||||
)
|
||||
@@ -135,9 +147,9 @@ watch(
|
||||
},
|
||||
)
|
||||
|
||||
// Watch districtId changes
|
||||
// Watch district_code changes
|
||||
watch(
|
||||
() => formRef.value?.values?.districtId,
|
||||
() => formRef.value?.values?.district_code,
|
||||
(newValue, oldValue) => {
|
||||
if (isResetting || !formRef.value || newValue === oldValue) return
|
||||
|
||||
@@ -146,8 +158,8 @@ watch(
|
||||
|
||||
formRef.value.setValues(
|
||||
{
|
||||
villageId: undefined,
|
||||
zipCode: undefined,
|
||||
village_code: undefined,
|
||||
postalRegion_code: undefined,
|
||||
},
|
||||
false,
|
||||
)
|
||||
@@ -159,9 +171,9 @@ watch(
|
||||
},
|
||||
)
|
||||
|
||||
// Watch villageId changes
|
||||
// Watch village_code changes
|
||||
watch(
|
||||
() => formRef.value?.values?.villageId,
|
||||
() => formRef.value?.values?.village_code,
|
||||
(newValue, oldValue) => {
|
||||
if (isResetting || !formRef.value || newValue === oldValue) return
|
||||
|
||||
@@ -170,7 +182,7 @@ watch(
|
||||
|
||||
formRef.value.setValues(
|
||||
{
|
||||
zipCode: undefined,
|
||||
postalRegion_code: undefined,
|
||||
},
|
||||
false,
|
||||
)
|
||||
@@ -188,19 +200,23 @@ watch(
|
||||
(newValue, oldValue) => {
|
||||
if (!formRef.value || newValue === oldValue) return
|
||||
|
||||
// Ketika berubah dari '1' ke '0', clear empty strings dan trigger validasi
|
||||
if (oldValue === '1' && newValue === '0') {
|
||||
// Konversi ke boolean untuk perbandingan yang konsisten
|
||||
const newBool = newValue === true || newValue === '1'
|
||||
const oldBool = oldValue === true || oldValue === '1'
|
||||
|
||||
// Ketika berubah dari true ke false, clear empty strings dan trigger validasi
|
||||
if (oldBool && !newBool) {
|
||||
nextTick(() => {
|
||||
// Set empty strings ke undefined untuk trigger required validation
|
||||
const currentValues = formRef.value.values
|
||||
const updatedValues = { ...currentValues }
|
||||
|
||||
// Convert empty strings to undefined untuk field yang sekarang required
|
||||
if (updatedValues.provinceId === '') updatedValues.provinceId = undefined
|
||||
if (updatedValues.regencyId === '') updatedValues.regencyId = undefined
|
||||
if (updatedValues.districtId === '') updatedValues.districtId = undefined
|
||||
if (updatedValues.villageId === '') updatedValues.villageId = undefined
|
||||
if (updatedValues.zipCode === '') updatedValues.zipCode = undefined
|
||||
if (updatedValues.province_code === '') updatedValues.province_code = undefined
|
||||
if (updatedValues.regency_code === '') updatedValues.regency_code = undefined
|
||||
if (updatedValues.district_code === '') updatedValues.district_code = undefined
|
||||
if (updatedValues.village_code === '') updatedValues.village_code = undefined
|
||||
if (updatedValues.postalRegion_code === '') updatedValues.postalRegion_code = undefined
|
||||
if (updatedValues.address === '') updatedValues.address = undefined
|
||||
|
||||
// Update values dan trigger validasi
|
||||
@@ -213,15 +229,15 @@ watch(
|
||||
})
|
||||
}
|
||||
|
||||
// Ketika berubah dari '0' ke '1', clear error messages
|
||||
if (oldValue === '0' && newValue === '1') {
|
||||
// Ketika berubah dari false ke true, clear error messages
|
||||
if (!oldBool && newBool) {
|
||||
nextTick(() => {
|
||||
// Clear error messages untuk field yang tidak lagi required
|
||||
formRef.value?.setFieldError('provinceId', undefined)
|
||||
formRef.value?.setFieldError('regencyId', undefined)
|
||||
formRef.value?.setFieldError('districtId', undefined)
|
||||
formRef.value?.setFieldError('villageId', undefined)
|
||||
formRef.value?.setFieldError('zipCode', undefined)
|
||||
formRef.value?.setFieldError('province_code', undefined)
|
||||
formRef.value?.setFieldError('regency_code', undefined)
|
||||
formRef.value?.setFieldError('district_code', undefined)
|
||||
formRef.value?.setFieldError('village_code', undefined)
|
||||
formRef.value?.setFieldError('postalRegion_code', undefined)
|
||||
formRef.value?.setFieldError('address', undefined)
|
||||
formRef.value?.setFieldError('rt', undefined)
|
||||
formRef.value?.setFieldError('rw', undefined)
|
||||
@@ -241,129 +257,138 @@ watch(
|
||||
:validation-schema="formSchema"
|
||||
:validate-on-mount="false"
|
||||
validation-mode="onSubmit"
|
||||
:initial-values="initialValues ?? { isSameAddress: '1' }"
|
||||
:initial-values="initialValues ?? { isSameAddress: '1', locationType_code: 'identity' }"
|
||||
>
|
||||
<div>
|
||||
<p
|
||||
v-if="props.title"
|
||||
class="text-md mb-2 mt-1 font-semibold"
|
||||
class="text-sm 2xl:text-base mb-2 2xl:mb-3 font-semibold"
|
||||
>
|
||||
{{ props.title }}
|
||||
</p>
|
||||
</div>
|
||||
<div class="mb-5 border-b border-b-slate-300 pb-3 text-lg xl:text-xl">
|
||||
<div class="grid grid-cols-1 gap-4 md:grid-cols-2 lg:grid-cols-2 xl:grid-cols-2">
|
||||
<!-- LocationType -->
|
||||
<FieldGroup v-if="conf?.withAddressName">
|
||||
<Label label-for="locationType">Jenis Alamat</Label>
|
||||
<Field
|
||||
id="locationType"
|
||||
:errors="errors"
|
||||
>
|
||||
<FormField
|
||||
v-slot="{ componentField }"
|
||||
name="locationType"
|
||||
>
|
||||
<FormItem>
|
||||
<FormControl>
|
||||
<Select
|
||||
id="locationType"
|
||||
v-bind="componentField"
|
||||
:items="[
|
||||
{ label: 'Rumah', value: 'rumah' },
|
||||
{ label: 'Kantor', value: 'kantor' },
|
||||
{ label: 'Lainnya', value: 'lainnya' },
|
||||
]"
|
||||
/>
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
</FormField>
|
||||
</Field>
|
||||
</FieldGroup>
|
||||
<RadioResidence field-name="isSameAddress" />
|
||||
<Block></Block>
|
||||
|
||||
<div class="flex-row gap-2 md:flex">
|
||||
<div class="min-w-0 flex-1">
|
||||
<SelectProvince
|
||||
field-name="provinceId"
|
||||
placeholder="Pilih"
|
||||
:is-disabled="values.isSameAddress === '1'"
|
||||
:is-required="values.isSameAddress !== '1'"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="min-w-0 flex-1">
|
||||
<SelectRegency
|
||||
field-name="regencyId"
|
||||
:placeholder="getFieldState('regencyId').placeholder"
|
||||
:is-disabled="getFieldState('regencyId').disabled || !values.provinceId"
|
||||
:is-required="values.isSameAddress !== '1'"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="flex-row gap-2 md:flex">
|
||||
<div class="min-w-0 flex-1">
|
||||
<SelectDistrict
|
||||
field-name="districtId"
|
||||
:placeholder="getFieldState('districtId').placeholder"
|
||||
:is-disabled="getFieldState('districtId').disabled || !values.regencyId"
|
||||
:is-required="values.isSameAddress !== '1'"
|
||||
/>
|
||||
</div>
|
||||
<div class="min-w-0 flex-1">
|
||||
<SelectVillage
|
||||
field-name="villageId"
|
||||
:placeholder="getFieldState('villageId').placeholder"
|
||||
:is-disabled="getFieldState('villageId').disabled || !values.districtId"
|
||||
:is-required="values.isSameAddress !== '1'"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<InputBase
|
||||
field-name="address"
|
||||
label="Alamat"
|
||||
:placeholder="getFieldState('address').placeholder"
|
||||
:is-disabled="getFieldState('address').disabled"
|
||||
<!-- locationType_code - Hidden field with default value 'identity' -->
|
||||
<FormField
|
||||
v-slot="{ componentField }"
|
||||
name="locationType_code"
|
||||
>
|
||||
<input
|
||||
type="hidden"
|
||||
v-bind="componentField"
|
||||
value="identity"
|
||||
/>
|
||||
</FormField>
|
||||
<DE.Block :col-count="4" :cell-flex="false">
|
||||
<DE.Cell :col-span="4">
|
||||
<DE.Label
|
||||
size="fit"
|
||||
height="compact"
|
||||
label-for="isSameAddress"
|
||||
>
|
||||
Apakah alamat KTP sama dengan alamat sekarang?
|
||||
</DE.Label>
|
||||
<DE.Field
|
||||
id="isSameAddress"
|
||||
:errors="errors"
|
||||
:is-required="values.isSameAddress !== '1'"
|
||||
>
|
||||
<FormField
|
||||
v-slot="{ componentField }"
|
||||
name="isSameAddress"
|
||||
>
|
||||
<FormItem>
|
||||
<FormControl>
|
||||
<RadioGroup
|
||||
:model-value="isSameAddressString"
|
||||
@update:model-value="(value) => componentField.onChange(value)"
|
||||
class="flex flex-row flex-wrap gap-4 sm:gap-6"
|
||||
>
|
||||
<div
|
||||
v-for="(option, index) in [
|
||||
{ label: 'Ya', value: '1' },
|
||||
{ label: 'Tidak', value: '0' },
|
||||
]"
|
||||
:key="option.value"
|
||||
class="flex min-w-fit items-center space-x-2"
|
||||
>
|
||||
<RadioGroupItem
|
||||
:id="`isSameAddress-${index}`"
|
||||
:value="option.value"
|
||||
class="relative h-4 w-4 rounded-full border-2 border-muted-foreground before:absolute before:inset-1 before:rounded-full before:bg-primary before:opacity-0 before:transition-opacity data-[state=checked]:border-primary data-[state=checked]:bg-white data-[state=checked]:before:opacity-100 sm:h-5 sm:w-5"
|
||||
/>
|
||||
<RadioLabel
|
||||
:for="`isSameAddress-${index}`"
|
||||
class="cursor-pointer select-none text-xs font-medium leading-none transition-colors hover:text-primary peer-disabled:cursor-not-allowed peer-disabled:opacity-70 sm:text-sm"
|
||||
>
|
||||
{{ option.label }}
|
||||
</RadioLabel>
|
||||
</div>
|
||||
</RadioGroup>
|
||||
</FormControl>
|
||||
<FormMessage class="ml-0 mt-1" />
|
||||
</FormItem>
|
||||
</FormField>
|
||||
</DE.Field>
|
||||
</DE.Cell>
|
||||
<SelectProvince
|
||||
field-name="province_code"
|
||||
placeholder="Pilih"
|
||||
:is-disabled="values.isSameAddress === true || values.isSameAddress === '1'"
|
||||
:is-required="values.isSameAddress !== true && values.isSameAddress !== '1'"
|
||||
/>
|
||||
<SelectRegency
|
||||
field-name="regency_code"
|
||||
:province-code="values.province_code"
|
||||
:is-disabled="getFieldState('regency_code').disabled"
|
||||
:is-required="values.isSameAddress !== true && values.isSameAddress !== '1'"
|
||||
/>
|
||||
<SelectDistrict
|
||||
field-name="district_code"
|
||||
:regency-code="values.regency_code"
|
||||
:is-disabled="getFieldState('district_code').disabled"
|
||||
:is-required="values.isSameAddress !== true && values.isSameAddress !== '1'"
|
||||
/>
|
||||
<SelectVillage
|
||||
field-name="village_code"
|
||||
:district-code="values.district_code"
|
||||
:is-disabled="getFieldState('village_code').disabled"
|
||||
:is-required="values.isSameAddress !== true && values.isSameAddress !== '1'"
|
||||
/>
|
||||
<InputBase
|
||||
field-name="address"
|
||||
label="Alamat"
|
||||
:placeholder="getFieldState('address').placeholder"
|
||||
:is-disabled="getFieldState('address').disabled"
|
||||
:errors="errors"
|
||||
:is-required="values.isSameAddress !== true && values.isSameAddress !== '1'"
|
||||
:col-span="2"
|
||||
/>
|
||||
<div class="grid grid-cols-2 gap-1">
|
||||
<InputBase
|
||||
field-name="rt"
|
||||
label="RT"
|
||||
:errors="errors"
|
||||
numeric-only
|
||||
:max-length="2"
|
||||
:placeholder="getFieldState('rt').placeholder"
|
||||
:is-disabled="getFieldState('rt').disabled"
|
||||
/>
|
||||
<InputBase
|
||||
field-name="rw"
|
||||
label="RW"
|
||||
:placeholder="getFieldState('rw').placeholder"
|
||||
:is-disabled="getFieldState('rw').disabled"
|
||||
:errors="errors"
|
||||
:max-length="2"
|
||||
numeric-only
|
||||
/>
|
||||
<div class="flex-row gap-2 md:flex">
|
||||
<div class="min-w-0 flex-1">
|
||||
<InputBase
|
||||
field-name="rt"
|
||||
label="RT"
|
||||
:errors="errors"
|
||||
numeric-only
|
||||
:max-length="3"
|
||||
:placeholder="getFieldState('rt').placeholder"
|
||||
:is-disabled="getFieldState('rt').disabled"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="min-w-0 flex-1">
|
||||
<InputBase
|
||||
field-name="rw"
|
||||
label="RW"
|
||||
:placeholder="getFieldState('rw').placeholder"
|
||||
:is-disabled="getFieldState('rw').disabled"
|
||||
:errors="errors"
|
||||
:max-length="3"
|
||||
numeric-only
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="min-w-0 flex-[2]">
|
||||
<SelectPostal
|
||||
field-name="zipCode"
|
||||
:placeholder="getFieldState('zipCode').placeholder"
|
||||
:is-disabled="getFieldState('zipCode').disabled || !values.villageId"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<SelectPostal
|
||||
field-name="postalRegion_code"
|
||||
:village-code="values.village_code"
|
||||
:placeholder="getFieldState('postalRegion_code').placeholder"
|
||||
:is-disabled="getFieldState('postalRegion_code').disabled || !values.village_code"
|
||||
/>
|
||||
</DE.Block>
|
||||
|
||||
</Form>
|
||||
</template>
|
||||
|
||||
@@ -12,6 +12,8 @@ import SelectRegency from './_common/select-regency.vue'
|
||||
import SelectVillage from './_common/select-village.vue'
|
||||
import { Form } from '~/components/pub/ui/form'
|
||||
|
||||
import * as DE from '~/components/pub/my-ui/doc-entry'
|
||||
|
||||
const props = defineProps<{
|
||||
title: string
|
||||
conf?: {
|
||||
@@ -35,29 +37,34 @@ defineExpose({
|
||||
// Watchers untuk cascading reset
|
||||
let isResetting = false
|
||||
|
||||
// #region Watch provinceId changes
|
||||
// #region Watch provinceCode changes
|
||||
|
||||
watch(
|
||||
() => formRef.value?.values?.provinceId,
|
||||
() => formRef.value?.values?.provinceCode,
|
||||
(newValue, oldValue) => {
|
||||
if (isResetting || !formRef.value || newValue === oldValue) return
|
||||
|
||||
if (oldValue && newValue !== oldValue) {
|
||||
isResetting = true
|
||||
|
||||
formRef.value.setValues(
|
||||
{
|
||||
regencyId: undefined,
|
||||
districtId: undefined,
|
||||
villageId: undefined,
|
||||
zipCode: undefined,
|
||||
},
|
||||
false,
|
||||
)
|
||||
// Delay reset untuk memberikan waktu composable menyelesaikan request
|
||||
setTimeout(() => {
|
||||
if (formRef.value) {
|
||||
formRef.value.setValues(
|
||||
{
|
||||
regencyId: undefined,
|
||||
districtId: undefined,
|
||||
villageId: undefined,
|
||||
zipCode: undefined,
|
||||
},
|
||||
false,
|
||||
)
|
||||
}
|
||||
|
||||
nextTick(() => {
|
||||
isResetting = false
|
||||
})
|
||||
nextTick(() => {
|
||||
isResetting = false
|
||||
})
|
||||
}, 150) // Delay 150ms, lebih dari debounce composable (100ms)
|
||||
}
|
||||
},
|
||||
)
|
||||
@@ -71,18 +78,23 @@ watch(
|
||||
if (oldValue && newValue !== oldValue) {
|
||||
isResetting = true
|
||||
|
||||
formRef.value.setValues(
|
||||
{
|
||||
districtId: undefined,
|
||||
villageId: undefined,
|
||||
zipCode: undefined,
|
||||
},
|
||||
false,
|
||||
)
|
||||
// Delay reset untuk memberikan waktu composable menyelesaikan request
|
||||
setTimeout(() => {
|
||||
if (formRef.value) {
|
||||
formRef.value.setValues(
|
||||
{
|
||||
districtId: undefined,
|
||||
villageId: undefined,
|
||||
zipCode: undefined,
|
||||
},
|
||||
false,
|
||||
)
|
||||
}
|
||||
|
||||
nextTick(() => {
|
||||
isResetting = false
|
||||
})
|
||||
nextTick(() => {
|
||||
isResetting = false
|
||||
})
|
||||
}, 150)
|
||||
}
|
||||
},
|
||||
)
|
||||
@@ -96,17 +108,22 @@ watch(
|
||||
if (oldValue && newValue !== oldValue) {
|
||||
isResetting = true
|
||||
|
||||
formRef.value.setValues(
|
||||
{
|
||||
villageId: undefined,
|
||||
zipCode: undefined,
|
||||
},
|
||||
false,
|
||||
)
|
||||
// Delay reset untuk memberikan waktu composable menyelesaikan request
|
||||
setTimeout(() => {
|
||||
if (formRef.value) {
|
||||
formRef.value.setValues(
|
||||
{
|
||||
villageId: undefined,
|
||||
zipCode: undefined,
|
||||
},
|
||||
false,
|
||||
)
|
||||
}
|
||||
|
||||
nextTick(() => {
|
||||
isResetting = false
|
||||
})
|
||||
nextTick(() => {
|
||||
isResetting = false
|
||||
})
|
||||
}, 150)
|
||||
}
|
||||
},
|
||||
)
|
||||
@@ -145,124 +162,84 @@ watch(
|
||||
:validation-schema="formSchema"
|
||||
:validate-on-mount="false"
|
||||
validation-mode="onSubmit"
|
||||
:initial-values="initialValues ? initialValues : {}"
|
||||
:initial-values="
|
||||
initialValues ? { locationType_code: 'domicile', ...initialValues } : { locationType_code: 'domicile' }
|
||||
"
|
||||
>
|
||||
<div>
|
||||
<p
|
||||
v-if="props.title"
|
||||
class="text-md mb-2 mt-1 font-semibold"
|
||||
class="text-sm 2xl:text-base mb-2 2xl:mb-3 font-semibold"
|
||||
>
|
||||
{{ props.title }}
|
||||
</p>
|
||||
</div>
|
||||
<div class="mb-5 border-b border-b-slate-300 pb-3 text-lg xl:text-xl">
|
||||
<div class="grid grid-cols-1 gap-4 md:grid-cols-2 lg:grid-cols-2 xl:grid-cols-2">
|
||||
<!-- LocationType -->
|
||||
<FieldGroup v-if="conf?.withAddressName">
|
||||
<Label label-for="locationType">Jenis Alamat</Label>
|
||||
<Field
|
||||
id="locationType"
|
||||
<FormField
|
||||
v-slot="{ componentField }"
|
||||
name="locationType_code"
|
||||
>
|
||||
<input
|
||||
type="hidden"
|
||||
v-bind="componentField"
|
||||
value="domicile"
|
||||
/>
|
||||
</FormField>
|
||||
|
||||
<DE.Block :col-count="4" :cell-flex="false">
|
||||
<SelectProvince
|
||||
field-name="province_code"
|
||||
placeholder="Pilih"
|
||||
is-required
|
||||
/>
|
||||
<SelectRegency
|
||||
field-name="regency_code"
|
||||
:province-code="values.province_code"
|
||||
is-required
|
||||
/>
|
||||
<SelectDistrict
|
||||
field-name="district_code"
|
||||
:regency-code="values.regency_code"
|
||||
is-required
|
||||
/>
|
||||
<SelectVillage
|
||||
field-name="village_code"
|
||||
:district-code="values.district_code"
|
||||
is-required
|
||||
/>
|
||||
<InputBase
|
||||
field-name="address"
|
||||
label="Alamat"
|
||||
placeholder="Masukkan alamat"
|
||||
:errors="errors"
|
||||
is-required
|
||||
:col-span="2"
|
||||
/>
|
||||
<DE.Cell class="flex-row gap-2">
|
||||
<div class="grid grid-cols-2 gap-1">
|
||||
<InputBase
|
||||
field-name="rt"
|
||||
label="RT"
|
||||
placeholder="01"
|
||||
:errors="errors"
|
||||
>
|
||||
<FormField
|
||||
v-slot="{ componentField }"
|
||||
name="locationType"
|
||||
>
|
||||
<FormItem>
|
||||
<FormControl>
|
||||
<Select
|
||||
id="locationType"
|
||||
v-bind="componentField"
|
||||
:items="[
|
||||
{ label: 'Rumah', value: 'rumah' },
|
||||
{ label: 'Kantor', value: 'kantor' },
|
||||
{ label: 'Lainnya', value: 'lainnya' },
|
||||
]"
|
||||
/>
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
</FormField>
|
||||
</Field>
|
||||
</FieldGroup>
|
||||
|
||||
<div class="flex-row gap-2 md:flex">
|
||||
<div class="min-w-0 flex-1">
|
||||
<SelectProvince
|
||||
field-name="provinceId"
|
||||
placeholder="Pilih"
|
||||
is-required
|
||||
numeric-only
|
||||
:max-length="2"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="min-w-0 flex-1">
|
||||
<SelectRegency
|
||||
field-name="regencyId"
|
||||
placeholder="Pilih provinsi dahulu"
|
||||
:is-disabled="!values.provinceId"
|
||||
is-required
|
||||
/>
|
||||
</div>
|
||||
<InputBase
|
||||
field-name="rw"
|
||||
label="RW"
|
||||
placeholder="02"
|
||||
:errors="errors"
|
||||
:max-length="2"
|
||||
numeric-only
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="flex-row gap-2 md:flex">
|
||||
<div class="min-w-0 flex-1">
|
||||
<SelectDistrict
|
||||
field-name="districtId"
|
||||
placeholder="Pilih kabupaten/kota dahulu"
|
||||
:is-disabled="!values.regencyId"
|
||||
is-required
|
||||
/>
|
||||
</div>
|
||||
<div class="min-w-0 flex-1">
|
||||
<SelectVillage
|
||||
field-name="villageId"
|
||||
placeholder="Pilih kecamatan dahulu"
|
||||
:is-disabled="!values.districtId"
|
||||
is-required
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<InputBase
|
||||
field-name="address"
|
||||
label="Alamat"
|
||||
placeholder="Masukkan alamat"
|
||||
:errors="errors"
|
||||
is-required
|
||||
</DE.Cell>
|
||||
<SelectPostal
|
||||
field-name="postalRegion_code"
|
||||
placeholder="Pilih kelurahan dahulu"
|
||||
:village-code="values.village_code"
|
||||
:is-disabled="!values.village_code"
|
||||
/>
|
||||
<div class="flex-row gap-2 md:flex">
|
||||
<div class="min-w-0 flex-1">
|
||||
<InputBase
|
||||
field-name="rt"
|
||||
label="RT"
|
||||
placeholder="001"
|
||||
:errors="errors"
|
||||
numeric-only
|
||||
:max-length="3"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="min-w-0 flex-1">
|
||||
<InputBase
|
||||
field-name="rw"
|
||||
label="RW"
|
||||
placeholder="002"
|
||||
:errors="errors"
|
||||
:max-length="3"
|
||||
numeric-only
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="min-w-0 flex-[2]">
|
||||
<SelectPostal
|
||||
field-name="zipCode"
|
||||
placeholder="Pilih kelurahan dahulu"
|
||||
:is-disabled="!values.villageId"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</DE.Block>
|
||||
</Form>
|
||||
</template>
|
||||
|
||||
@@ -39,7 +39,7 @@ defineExpose({
|
||||
<div>
|
||||
<p
|
||||
v-if="props.title"
|
||||
class="text-md mb-2 mt-1 font-semibold"
|
||||
class="text-sm 2xl:text-base mb-2 2xl:mb-3 font-semibold"
|
||||
>
|
||||
{{ props.title || 'Kontak Pasien' }}
|
||||
</p>
|
||||
@@ -94,6 +94,7 @@ defineExpose({
|
||||
:disabled="fields.length >= contactLimit"
|
||||
type="button"
|
||||
variant="outline"
|
||||
size="sm"
|
||||
@click="push({ contactType: '', contactNumber: '' })"
|
||||
>
|
||||
<Icon
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user