Fix: refactor rehab medik - Resume UI
This commit is contained in:
@@ -0,0 +1,22 @@
|
||||
<script setup lang="ts">
|
||||
import type { ListItemDto } from '~/components/pub/my-ui/data/types';
|
||||
|
||||
const props = defineProps<{
|
||||
url: string
|
||||
btnTxt?: string
|
||||
rec: ListItemDto
|
||||
}>()
|
||||
|
||||
function handlePrint() {
|
||||
navigateTo(props.url || 'https://google.com', {external: true,open: { target: "_blank" },});
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Button
|
||||
class="gap-3 items-center border-orange-400 text-orange-400"
|
||||
variant="outline" @click="handlePrint">
|
||||
<Icon name="i-lucide-printer" class="h-4 w-4" />
|
||||
{{ props.btnTxt || 'Lampiran' }}
|
||||
</Button>
|
||||
</template>
|
||||
@@ -0,0 +1,70 @@
|
||||
<script setup lang="ts">
|
||||
import type { FormErrors } from '~/types/error'
|
||||
import Combobox from '~/components/pub/my-ui/combobox/combobox.vue'
|
||||
import { cn, mapToComboboxOptList } from '~/lib/utils'
|
||||
import { occupationCodes } from '~/lib/constants'
|
||||
|
||||
import * as DE from '~/components/pub/my-ui/doc-entry'
|
||||
|
||||
const props = defineProps<{
|
||||
fieldName?: string
|
||||
label?: string
|
||||
placeholder?: string
|
||||
errors?: FormErrors
|
||||
class?: string
|
||||
selectClass?: string
|
||||
fieldGroupClass?: string
|
||||
labelClass?: string
|
||||
isRequired?: boolean
|
||||
}>()
|
||||
|
||||
const {
|
||||
fieldName = 'job',
|
||||
label = 'Pekerjaan',
|
||||
placeholder = 'Pilih pekerjaan',
|
||||
errors,
|
||||
class: containerClass,
|
||||
fieldGroupClass,
|
||||
labelClass,
|
||||
} = props
|
||||
|
||||
// Generate job options from constants, sama seperti pola genderCodes
|
||||
const jobOptions = mapToComboboxOptList(occupationCodes)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<DE.Cell :class="cn('select-field-group', fieldGroupClass, containerClass)">
|
||||
<DE.Label
|
||||
:label-for="fieldName"
|
||||
:class="cn('select-field-label', labelClass)"
|
||||
:is-required="isRequired"
|
||||
>
|
||||
{{ label }}
|
||||
</DE.Label>
|
||||
<DE.Field
|
||||
:id="fieldName"
|
||||
:errors="errors"
|
||||
:class="cn('select-field-wrapper')"
|
||||
>
|
||||
<FormField
|
||||
v-slot="{ componentField }"
|
||||
:name="fieldName"
|
||||
>
|
||||
<FormItem>
|
||||
<FormControl>
|
||||
<Combobox
|
||||
class="focus:ring-0 focus:ring-offset-0"
|
||||
:id="fieldName"
|
||||
v-bind="componentField"
|
||||
:items="jobOptions"
|
||||
:placeholder="placeholder"
|
||||
search-placeholder="Cari..."
|
||||
empty-message="Data tidak ditemukan"
|
||||
/>
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
</FormField>
|
||||
</DE.Field>
|
||||
</DE.Cell>
|
||||
</template>
|
||||
@@ -0,0 +1,70 @@
|
||||
<script setup lang="ts">
|
||||
import type { FormErrors } from '~/types/error'
|
||||
import Combobox from '~/components/pub/my-ui/combobox/combobox.vue'
|
||||
import { cn, mapToComboboxOptList } from '~/lib/utils'
|
||||
import { occupationCodes } from '~/lib/constants'
|
||||
|
||||
import * as DE from '~/components/pub/my-ui/doc-entry'
|
||||
|
||||
const props = defineProps<{
|
||||
fieldName?: string
|
||||
label?: string
|
||||
placeholder?: string
|
||||
errors?: FormErrors
|
||||
class?: string
|
||||
selectClass?: string
|
||||
fieldGroupClass?: string
|
||||
labelClass?: string
|
||||
isRequired?: boolean
|
||||
}>()
|
||||
|
||||
const {
|
||||
fieldName = 'job',
|
||||
label = 'Pekerjaan',
|
||||
placeholder = 'Pilih pekerjaan',
|
||||
errors,
|
||||
class: containerClass,
|
||||
fieldGroupClass,
|
||||
labelClass,
|
||||
} = props
|
||||
|
||||
// Generate job options from constants, sama seperti pola genderCodes
|
||||
const jobOptions = mapToComboboxOptList(occupationCodes)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<DE.Cell :class="cn('select-field-group', fieldGroupClass, containerClass)">
|
||||
<DE.Label
|
||||
:label-for="fieldName"
|
||||
:class="cn('select-field-label', labelClass)"
|
||||
:is-required="isRequired"
|
||||
>
|
||||
{{ label }}
|
||||
</DE.Label>
|
||||
<DE.Field
|
||||
:id="fieldName"
|
||||
:errors="errors"
|
||||
:class="cn('select-field-wrapper')"
|
||||
>
|
||||
<FormField
|
||||
v-slot="{ componentField }"
|
||||
:name="fieldName"
|
||||
>
|
||||
<FormItem>
|
||||
<FormControl>
|
||||
<Combobox
|
||||
class="focus:ring-0 focus:ring-offset-0"
|
||||
:id="fieldName"
|
||||
v-bind="componentField"
|
||||
:items="jobOptions"
|
||||
:placeholder="placeholder"
|
||||
search-placeholder="Cari..."
|
||||
empty-message="Data tidak ditemukan"
|
||||
/>
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
</FormField>
|
||||
</DE.Field>
|
||||
</DE.Cell>
|
||||
</template>
|
||||
@@ -0,0 +1,70 @@
|
||||
<script setup lang="ts">
|
||||
import type { FormErrors } from '~/types/error'
|
||||
import Combobox from '~/components/pub/my-ui/combobox/combobox.vue'
|
||||
import { cn, mapToComboboxOptList } from '~/lib/utils'
|
||||
import { occupationCodes } from '~/lib/constants'
|
||||
|
||||
import * as DE from '~/components/pub/my-ui/doc-entry'
|
||||
|
||||
const props = defineProps<{
|
||||
fieldName?: string
|
||||
label?: string
|
||||
placeholder?: string
|
||||
errors?: FormErrors
|
||||
class?: string
|
||||
selectClass?: string
|
||||
fieldGroupClass?: string
|
||||
labelClass?: string
|
||||
isRequired?: boolean
|
||||
}>()
|
||||
|
||||
const {
|
||||
fieldName = 'job',
|
||||
label = 'Pekerjaan',
|
||||
placeholder = 'Pilih pekerjaan',
|
||||
errors,
|
||||
class: containerClass,
|
||||
fieldGroupClass,
|
||||
labelClass,
|
||||
} = props
|
||||
|
||||
// Generate job options from constants, sama seperti pola genderCodes
|
||||
const jobOptions = mapToComboboxOptList(occupationCodes)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<DE.Cell :class="cn('select-field-group', fieldGroupClass, containerClass)">
|
||||
<DE.Label
|
||||
:label-for="fieldName"
|
||||
:class="cn('select-field-label', labelClass)"
|
||||
:is-required="isRequired"
|
||||
>
|
||||
{{ label }}
|
||||
</DE.Label>
|
||||
<DE.Field
|
||||
:id="fieldName"
|
||||
:errors="errors"
|
||||
:class="cn('select-field-wrapper')"
|
||||
>
|
||||
<FormField
|
||||
v-slot="{ componentField }"
|
||||
:name="fieldName"
|
||||
>
|
||||
<FormItem>
|
||||
<FormControl>
|
||||
<Combobox
|
||||
class="focus:ring-0 focus:ring-offset-0"
|
||||
:id="fieldName"
|
||||
v-bind="componentField"
|
||||
:items="jobOptions"
|
||||
:placeholder="placeholder"
|
||||
search-placeholder="Cari..."
|
||||
empty-message="Data tidak ditemukan"
|
||||
/>
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
</FormField>
|
||||
</DE.Field>
|
||||
</DE.Cell>
|
||||
</template>
|
||||
@@ -0,0 +1,70 @@
|
||||
<script setup lang="ts">
|
||||
import type { FormErrors } from '~/types/error'
|
||||
import Combobox from '~/components/pub/my-ui/combobox/combobox.vue'
|
||||
import { cn, mapToComboboxOptList } from '~/lib/utils'
|
||||
import { occupationCodes } from '~/lib/constants'
|
||||
|
||||
import * as DE from '~/components/pub/my-ui/doc-entry'
|
||||
|
||||
const props = defineProps<{
|
||||
fieldName?: string
|
||||
label?: string
|
||||
placeholder?: string
|
||||
errors?: FormErrors
|
||||
class?: string
|
||||
selectClass?: string
|
||||
fieldGroupClass?: string
|
||||
labelClass?: string
|
||||
isRequired?: boolean
|
||||
}>()
|
||||
|
||||
const {
|
||||
fieldName = 'job',
|
||||
label = 'Pekerjaan',
|
||||
placeholder = 'Pilih pekerjaan',
|
||||
errors,
|
||||
class: containerClass,
|
||||
fieldGroupClass,
|
||||
labelClass,
|
||||
} = props
|
||||
|
||||
// Generate job options from constants, sama seperti pola genderCodes
|
||||
const jobOptions = mapToComboboxOptList(occupationCodes)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<DE.Cell :class="cn('select-field-group', fieldGroupClass, containerClass)">
|
||||
<DE.Label
|
||||
:label-for="fieldName"
|
||||
:class="cn('select-field-label', labelClass)"
|
||||
:is-required="isRequired"
|
||||
>
|
||||
{{ label }}
|
||||
</DE.Label>
|
||||
<DE.Field
|
||||
:id="fieldName"
|
||||
:errors="errors"
|
||||
:class="cn('select-field-wrapper')"
|
||||
>
|
||||
<FormField
|
||||
v-slot="{ componentField }"
|
||||
:name="fieldName"
|
||||
>
|
||||
<FormItem>
|
||||
<FormControl>
|
||||
<Combobox
|
||||
class="focus:ring-0 focus:ring-offset-0"
|
||||
:id="fieldName"
|
||||
v-bind="componentField"
|
||||
:items="jobOptions"
|
||||
:placeholder="placeholder"
|
||||
search-placeholder="Cari..."
|
||||
empty-message="Data tidak ditemukan"
|
||||
/>
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
</FormField>
|
||||
</DE.Field>
|
||||
</DE.Cell>
|
||||
</template>
|
||||
@@ -0,0 +1,70 @@
|
||||
<script setup lang="ts">
|
||||
import type { FormErrors } from '~/types/error'
|
||||
import Combobox from '~/components/pub/my-ui/combobox/combobox.vue'
|
||||
import { cn, mapToComboboxOptList } from '~/lib/utils'
|
||||
import { occupationCodes } from '~/lib/constants'
|
||||
|
||||
import * as DE from '~/components/pub/my-ui/doc-entry'
|
||||
|
||||
const props = defineProps<{
|
||||
fieldName?: string
|
||||
label?: string
|
||||
placeholder?: string
|
||||
errors?: FormErrors
|
||||
class?: string
|
||||
selectClass?: string
|
||||
fieldGroupClass?: string
|
||||
labelClass?: string
|
||||
isRequired?: boolean
|
||||
}>()
|
||||
|
||||
const {
|
||||
fieldName = 'job',
|
||||
label = 'Pekerjaan',
|
||||
placeholder = 'Pilih pekerjaan',
|
||||
errors,
|
||||
class: containerClass,
|
||||
fieldGroupClass,
|
||||
labelClass,
|
||||
} = props
|
||||
|
||||
// Generate job options from constants, sama seperti pola genderCodes
|
||||
const jobOptions = mapToComboboxOptList(occupationCodes)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<DE.Cell :class="cn('select-field-group', fieldGroupClass, containerClass)">
|
||||
<DE.Label
|
||||
:label-for="fieldName"
|
||||
:class="cn('select-field-label', labelClass)"
|
||||
:is-required="isRequired"
|
||||
>
|
||||
{{ label }}
|
||||
</DE.Label>
|
||||
<DE.Field
|
||||
:id="fieldName"
|
||||
:errors="errors"
|
||||
:class="cn('select-field-wrapper')"
|
||||
>
|
||||
<FormField
|
||||
v-slot="{ componentField }"
|
||||
:name="fieldName"
|
||||
>
|
||||
<FormItem>
|
||||
<FormControl>
|
||||
<Combobox
|
||||
class="focus:ring-0 focus:ring-offset-0"
|
||||
:id="fieldName"
|
||||
v-bind="componentField"
|
||||
:items="jobOptions"
|
||||
:placeholder="placeholder"
|
||||
search-placeholder="Cari..."
|
||||
empty-message="Data tidak ditemukan"
|
||||
/>
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
</FormField>
|
||||
</DE.Field>
|
||||
</DE.Cell>
|
||||
</template>
|
||||
@@ -0,0 +1,70 @@
|
||||
<script setup lang="ts">
|
||||
import type { FormErrors } from '~/types/error'
|
||||
import Combobox from '~/components/pub/my-ui/combobox/combobox.vue'
|
||||
import { cn, mapToComboboxOptList } from '~/lib/utils'
|
||||
import { occupationCodes } from '~/lib/constants'
|
||||
|
||||
import * as DE from '~/components/pub/my-ui/doc-entry'
|
||||
|
||||
const props = defineProps<{
|
||||
fieldName?: string
|
||||
label?: string
|
||||
placeholder?: string
|
||||
errors?: FormErrors
|
||||
class?: string
|
||||
selectClass?: string
|
||||
fieldGroupClass?: string
|
||||
labelClass?: string
|
||||
isRequired?: boolean
|
||||
}>()
|
||||
|
||||
const {
|
||||
fieldName = 'job',
|
||||
label = 'Pekerjaan',
|
||||
placeholder = 'Pilih pekerjaan',
|
||||
errors,
|
||||
class: containerClass,
|
||||
fieldGroupClass,
|
||||
labelClass,
|
||||
} = props
|
||||
|
||||
// Generate job options from constants, sama seperti pola genderCodes
|
||||
const jobOptions = mapToComboboxOptList(occupationCodes)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<DE.Cell :class="cn('select-field-group', fieldGroupClass, containerClass)">
|
||||
<DE.Label
|
||||
:label-for="fieldName"
|
||||
:class="cn('select-field-label', labelClass)"
|
||||
:is-required="isRequired"
|
||||
>
|
||||
{{ label }}
|
||||
</DE.Label>
|
||||
<DE.Field
|
||||
:id="fieldName"
|
||||
:errors="errors"
|
||||
:class="cn('select-field-wrapper')"
|
||||
>
|
||||
<FormField
|
||||
v-slot="{ componentField }"
|
||||
:name="fieldName"
|
||||
>
|
||||
<FormItem>
|
||||
<FormControl>
|
||||
<Combobox
|
||||
class="focus:ring-0 focus:ring-offset-0"
|
||||
:id="fieldName"
|
||||
v-bind="componentField"
|
||||
:items="jobOptions"
|
||||
:placeholder="placeholder"
|
||||
search-placeholder="Cari..."
|
||||
empty-message="Data tidak ditemukan"
|
||||
/>
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
</FormField>
|
||||
</DE.Field>
|
||||
</DE.Cell>
|
||||
</template>
|
||||
@@ -0,0 +1,70 @@
|
||||
<script setup lang="ts">
|
||||
import type { FormErrors } from '~/types/error'
|
||||
import Combobox from '~/components/pub/my-ui/combobox/combobox.vue'
|
||||
import { cn, mapToComboboxOptList } from '~/lib/utils'
|
||||
import { occupationCodes } from '~/lib/constants'
|
||||
|
||||
import * as DE from '~/components/pub/my-ui/doc-entry'
|
||||
|
||||
const props = defineProps<{
|
||||
fieldName?: string
|
||||
label?: string
|
||||
placeholder?: string
|
||||
errors?: FormErrors
|
||||
class?: string
|
||||
selectClass?: string
|
||||
fieldGroupClass?: string
|
||||
labelClass?: string
|
||||
isRequired?: boolean
|
||||
}>()
|
||||
|
||||
const {
|
||||
fieldName = 'job',
|
||||
label = 'Pekerjaan',
|
||||
placeholder = 'Pilih pekerjaan',
|
||||
errors,
|
||||
class: containerClass,
|
||||
fieldGroupClass,
|
||||
labelClass,
|
||||
} = props
|
||||
|
||||
// Generate job options from constants, sama seperti pola genderCodes
|
||||
const jobOptions = mapToComboboxOptList(occupationCodes)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<DE.Cell :class="cn('select-field-group', fieldGroupClass, containerClass)">
|
||||
<DE.Label
|
||||
:label-for="fieldName"
|
||||
:class="cn('select-field-label', labelClass)"
|
||||
:is-required="isRequired"
|
||||
>
|
||||
{{ label }}
|
||||
</DE.Label>
|
||||
<DE.Field
|
||||
:id="fieldName"
|
||||
:errors="errors"
|
||||
:class="cn('select-field-wrapper')"
|
||||
>
|
||||
<FormField
|
||||
v-slot="{ componentField }"
|
||||
:name="fieldName"
|
||||
>
|
||||
<FormItem>
|
||||
<FormControl>
|
||||
<Combobox
|
||||
class="focus:ring-0 focus:ring-offset-0"
|
||||
:id="fieldName"
|
||||
v-bind="componentField"
|
||||
:items="jobOptions"
|
||||
:placeholder="placeholder"
|
||||
search-placeholder="Cari..."
|
||||
empty-message="Data tidak ditemukan"
|
||||
/>
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
</FormField>
|
||||
</DE.Field>
|
||||
</DE.Cell>
|
||||
</template>
|
||||
@@ -0,0 +1,70 @@
|
||||
<script setup lang="ts">
|
||||
import type { FormErrors } from '~/types/error'
|
||||
import Combobox from '~/components/pub/my-ui/combobox/combobox.vue'
|
||||
import { cn, mapToComboboxOptList } from '~/lib/utils'
|
||||
import { occupationCodes } from '~/lib/constants'
|
||||
|
||||
import * as DE from '~/components/pub/my-ui/doc-entry'
|
||||
|
||||
const props = defineProps<{
|
||||
fieldName?: string
|
||||
label?: string
|
||||
placeholder?: string
|
||||
errors?: FormErrors
|
||||
class?: string
|
||||
selectClass?: string
|
||||
fieldGroupClass?: string
|
||||
labelClass?: string
|
||||
isRequired?: boolean
|
||||
}>()
|
||||
|
||||
const {
|
||||
fieldName = 'job',
|
||||
label = 'Pekerjaan',
|
||||
placeholder = 'Pilih pekerjaan',
|
||||
errors,
|
||||
class: containerClass,
|
||||
fieldGroupClass,
|
||||
labelClass,
|
||||
} = props
|
||||
|
||||
// Generate job options from constants, sama seperti pola genderCodes
|
||||
const jobOptions = mapToComboboxOptList(occupationCodes)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<DE.Cell :class="cn('select-field-group', fieldGroupClass, containerClass)">
|
||||
<DE.Label
|
||||
:label-for="fieldName"
|
||||
:class="cn('select-field-label', labelClass)"
|
||||
:is-required="isRequired"
|
||||
>
|
||||
{{ label }}
|
||||
</DE.Label>
|
||||
<DE.Field
|
||||
:id="fieldName"
|
||||
:errors="errors"
|
||||
:class="cn('select-field-wrapper')"
|
||||
>
|
||||
<FormField
|
||||
v-slot="{ componentField }"
|
||||
:name="fieldName"
|
||||
>
|
||||
<FormItem>
|
||||
<FormControl>
|
||||
<Combobox
|
||||
class="focus:ring-0 focus:ring-offset-0"
|
||||
:id="fieldName"
|
||||
v-bind="componentField"
|
||||
:items="jobOptions"
|
||||
:placeholder="placeholder"
|
||||
search-placeholder="Cari..."
|
||||
empty-message="Data tidak ditemukan"
|
||||
/>
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
</FormField>
|
||||
</DE.Field>
|
||||
</DE.Cell>
|
||||
</template>
|
||||
@@ -0,0 +1,70 @@
|
||||
<script setup lang="ts">
|
||||
import type { FormErrors } from '~/types/error'
|
||||
import Combobox from '~/components/pub/my-ui/combobox/combobox.vue'
|
||||
import { cn, mapToComboboxOptList } from '~/lib/utils'
|
||||
import { occupationCodes } from '~/lib/constants'
|
||||
|
||||
import * as DE from '~/components/pub/my-ui/doc-entry'
|
||||
|
||||
const props = defineProps<{
|
||||
fieldName?: string
|
||||
label?: string
|
||||
placeholder?: string
|
||||
errors?: FormErrors
|
||||
class?: string
|
||||
selectClass?: string
|
||||
fieldGroupClass?: string
|
||||
labelClass?: string
|
||||
isRequired?: boolean
|
||||
}>()
|
||||
|
||||
const {
|
||||
fieldName = 'job',
|
||||
label = 'Pekerjaan',
|
||||
placeholder = 'Pilih pekerjaan',
|
||||
errors,
|
||||
class: containerClass,
|
||||
fieldGroupClass,
|
||||
labelClass,
|
||||
} = props
|
||||
|
||||
// Generate job options from constants, sama seperti pola genderCodes
|
||||
const jobOptions = mapToComboboxOptList(occupationCodes)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<DE.Cell :class="cn('select-field-group', fieldGroupClass, containerClass)">
|
||||
<DE.Label
|
||||
:label-for="fieldName"
|
||||
:class="cn('select-field-label', labelClass)"
|
||||
:is-required="isRequired"
|
||||
>
|
||||
{{ label }}
|
||||
</DE.Label>
|
||||
<DE.Field
|
||||
:id="fieldName"
|
||||
:errors="errors"
|
||||
:class="cn('select-field-wrapper')"
|
||||
>
|
||||
<FormField
|
||||
v-slot="{ componentField }"
|
||||
:name="fieldName"
|
||||
>
|
||||
<FormItem>
|
||||
<FormControl>
|
||||
<Combobox
|
||||
class="focus:ring-0 focus:ring-offset-0"
|
||||
:id="fieldName"
|
||||
v-bind="componentField"
|
||||
:items="jobOptions"
|
||||
:placeholder="placeholder"
|
||||
search-placeholder="Cari..."
|
||||
empty-message="Data tidak ditemukan"
|
||||
/>
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
</FormField>
|
||||
</DE.Field>
|
||||
</DE.Cell>
|
||||
</template>
|
||||
@@ -0,0 +1,67 @@
|
||||
<script setup lang="ts">
|
||||
import { Badge, type Variants } from '~/components/pub/ui/badge'
|
||||
|
||||
const activeStatusCodes: Record<string, string> = {
|
||||
verified: 'Terverifikasi',
|
||||
validated: 'Tervalidasi',
|
||||
unverified: 'Belum Verifikasi',
|
||||
unvalidated: 'Batal Validasi',
|
||||
}
|
||||
|
||||
const props = defineProps<{
|
||||
rec: any
|
||||
idx?: number
|
||||
}>()
|
||||
|
||||
const statusText = computed(() => {
|
||||
let code: keyof typeof activeStatusCodes = `unverified`
|
||||
switch (props.rec.status_code) {
|
||||
case 1:
|
||||
code = 'verified'
|
||||
break
|
||||
case 2:
|
||||
code = 'validated'
|
||||
break
|
||||
case 3:
|
||||
code = 'unverified'
|
||||
break
|
||||
case 4:
|
||||
code = 'unvalidated'
|
||||
break
|
||||
default:
|
||||
code = 'unverified'
|
||||
break
|
||||
}
|
||||
return activeStatusCodes[code]
|
||||
})
|
||||
|
||||
const badgeVariant = computed(() => {
|
||||
let variant: Variants = `outline`
|
||||
switch (props.rec.status_code) {
|
||||
case 1:
|
||||
variant = 'secondary'
|
||||
break
|
||||
case 2:
|
||||
variant = 'default'
|
||||
break
|
||||
case 3:
|
||||
variant = 'outline'
|
||||
break
|
||||
case 4:
|
||||
variant = 'destructive'
|
||||
break
|
||||
default:
|
||||
variant = 'outline'
|
||||
break
|
||||
}
|
||||
return variant
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="flex justify-center">
|
||||
<Badge :variant="badgeVariant" class="rounded-2xl text-[0.6rem]" >
|
||||
{{ statusText }}
|
||||
</Badge>
|
||||
</div>
|
||||
</template>
|
||||
@@ -8,12 +8,19 @@ import InputBase from '~/components/pub/my-ui/form/input-base.vue'
|
||||
|
||||
import * as DE from '~/components/pub/my-ui/doc-entry'
|
||||
import TextAreaInput from '~/components/pub/my-ui/form/text-area-input.vue'
|
||||
import SelectSecondaryDiagnosis from './_common/select-secondary-diagnosis.vue'
|
||||
import SelectPrimaryDiagnosis from './_common/select-primary-diagnosis.vue'
|
||||
import SelectArrangement from './_common/select-arrangement.vue'
|
||||
import type { ResumeArrangementType } from '~/schemas/resume.schema'
|
||||
import SelectFaskes from './_common/select-faskes.vue'
|
||||
import SelectDeathCause from './_common/select-death-cause.vue'
|
||||
import SelectIcd10 from './_common/select-icd-10.vue'
|
||||
import SelectIcd9 from './_common/select-icd-9.vue'
|
||||
import SelectConciousLevel from './_common/select-concious-level.vue'
|
||||
import SelectPainScale from './_common/select-pain-scale.vue'
|
||||
import SelectNationalProgramService from './_common/select-national-program-service.vue'
|
||||
import SelectNationalProgramServiceStatus from './_common/select-national-program-service-status.vue'
|
||||
import SelectHospitalLeaveCondition from './_common/select-hospital-leave-condition.vue'
|
||||
import SelectFollowingArrangement from './_common/select-following-arrangement.vue'
|
||||
import SelectHospitalLeaveMethod from './_common/select-hospital-leave-method.vue'
|
||||
|
||||
const props = defineProps<{
|
||||
schema: any
|
||||
@@ -22,6 +29,11 @@ const props = defineProps<{
|
||||
errors?: FormErrors
|
||||
}>()
|
||||
|
||||
const isActionHistoryOpen = inject(`isActionHistoryOpen`) as Ref<boolean>
|
||||
const isConsultationHistoryOpen = inject(`isConsultationHistoryOpen`) as Ref<boolean>
|
||||
const isSupportingHistoryOpen = inject(`isSupportingHistoryOpen`) as Ref<boolean>
|
||||
const isFarmacyHistoryOpen = inject(`isFarmacyHistoryOpen`) as Ref<boolean>
|
||||
const isNationalProgramServiceHistoryOpen = inject(`isNationalProgramServiceHistoryOpen`) as Ref<boolean>
|
||||
const formSchema = toTypedSchema(props.schema)
|
||||
const formRef = ref()
|
||||
|
||||
@@ -31,101 +43,369 @@ defineExpose({
|
||||
setValues: (values: any, shouldValidate = true) => formRef.value?.setValues(values, shouldValidate),
|
||||
values: computed(() => formRef.value?.values),
|
||||
})
|
||||
|
||||
const DEFAULT_SECONDARY_DIAGNOSIS_VALUE = {
|
||||
diagnosis: '',
|
||||
icd10: '',
|
||||
diagnosisBasis: '',
|
||||
};
|
||||
const DEFAULT_SECONDARY_ACTION_VALUE = {
|
||||
action: '',
|
||||
icd9: '',
|
||||
actionBasis: '',
|
||||
};
|
||||
const DEFAULT_CONSULTATION_VALUE = {
|
||||
consultation: '',
|
||||
consultationReply: '',
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Form ref="formRef" v-slot="{ values }" as="" keep-values :validation-schema="formSchema" :validate-on-mount="false"
|
||||
validation-mode="onSubmit" :initial-values="initialValues ? initialValues : {}">
|
||||
<Form ref="formRef"
|
||||
v-slot="{ values }"
|
||||
as=""
|
||||
keep-values
|
||||
:validation-schema="formSchema"
|
||||
:validate-on-mount="false"
|
||||
validation-mode="onSubmit"
|
||||
:initial-values="initialValues ? initialValues : {}">
|
||||
|
||||
<!-- Pasien -->
|
||||
<h1 class="mb-3 text-base font-medium">Pemeriksaan Pasien</h1>
|
||||
<DE.Block :col-count="3" :cell-flex="false">
|
||||
<SelectDate field-name="inDate" label="Tanggal Masuk" :errors="errors" :is-disabled="true" />
|
||||
<SelectDate field-name="outDate" label="Tanggal Keluar" :errors="errors" :is-disabled="true" />
|
||||
</DE.Block>
|
||||
<SelectDate field-name="outDate" label="Tanggal Keluar" :errors="errors" :is-disabled="true" />
|
||||
<InputBase
|
||||
field-name="doctor_id"
|
||||
:is-disabled="true"
|
||||
label="DPJP" placeholder="DPJP"/>
|
||||
</DE.Block>
|
||||
<DE.Block class="" :cell-flex="false">
|
||||
<InputBase
|
||||
class="w-2/3"
|
||||
field-name="first_diagnosis"
|
||||
:is-disabled="true"
|
||||
label="Diagnosis Masuk/Rujukan" placeholder="Diagnosis Masuk/Rujukan"/>
|
||||
</DE.Block>
|
||||
<DE.Block :col-count="3" :cell-flex="false">
|
||||
<TextAreaInput field-name="anamnesis" label="Anamnesis" placeholder="Anamnesis" :errors="errors" />
|
||||
<TextAreaInput field-name="physicalCheckup" label="Pemeriksaan Fisik" placeholder="Pemeriksaan Fisik"
|
||||
:errors="errors" />
|
||||
<TextAreaInput field-name="supplementCheckup" label="Pemeriksaan Penunjang" placeholder="Pemeriksaan Penunjang"
|
||||
:errors="errors" />
|
||||
<TextAreaInput field-name="supplementCheckup"
|
||||
label="Indikasi Rawat Jalan" placeholder="Indikasi Rawat Jalan" :errors="errors" />
|
||||
<TextAreaInput field-name="supplementCheckup"
|
||||
label="Keluhan Utama (Singkat & Menunjang)" placeholder="Keluhan Utama (Singkat & Menunjang)" :errors="errors" />
|
||||
<TextAreaInput field-name="supplementCheckup"
|
||||
label="Pemeriksaan Fisik (Singkat & Menunjang)" placeholder="Pemeriksaan Fisik (Singkat & Menunjang)" :errors="errors" />
|
||||
<TextAreaInput field-name="supplementCheckup"
|
||||
label="Riwayat Penyakit" placeholder="Riwayat Penyakit" :errors="errors" />
|
||||
<TextAreaInput field-name="supplementCheckup"
|
||||
label="Diagnosa Medis" placeholder="Diagnosa Medis" :errors="errors" />
|
||||
</DE.Block>
|
||||
<Separator class="my-4" />
|
||||
|
||||
|
||||
|
||||
<!-- DIAGNOSIS -->
|
||||
<h1 class="mb-3 text-base font-medium">Diagnosis</h1>
|
||||
<DE.Block class="w-3/5 space-y-2" :cell-flex="false">
|
||||
<SelectPrimaryDiagnosis
|
||||
<h1 class="mb-3 text-base font-medium">Diagnosa</h1>
|
||||
<h1 class="mb-3 text-base font-medium">Diagnosa Utama</h1>
|
||||
<DE.Block :col-count="2" class="" :cell-flex="false">
|
||||
<InputBase
|
||||
field-name="diagnosis"
|
||||
label="Diagnosa" placeholder="Masukkan Diagnosa"
|
||||
:errors="errors" is-required />
|
||||
<SelectIcd10
|
||||
field-name="primaryDiagnosis"
|
||||
label="Diagnosis Utama"
|
||||
placeholder="Diagnosis Utama"
|
||||
label="ICD 10"
|
||||
placeholder="ICD 10"
|
||||
:errors="errors" is-required />
|
||||
<DE.Cell :col-span="2">
|
||||
<TextAreaInput field-name="supplementCheckup"
|
||||
label="Dasar Diagnosa" placeholder="Masukkan Dasar Diagnosa utama Pasien" :errors="errors" />
|
||||
</DE.Cell>
|
||||
|
||||
<div class="w-full rounded-md border bg-gray-50/50 p-4 shadow-sm dark:bg-neutral-950">
|
||||
<h1 class="mb-3 font-medium">Diagnosis Sekunder</h1>
|
||||
|
||||
<FieldArray v-slot="{ fields, push, remove }" name="secondaryDiagnosis">
|
||||
<div v-for="(field, idx) in fields" :key="idx" class="flex items-center gap-3 mb-3">
|
||||
<SelectSecondaryDiagnosis
|
||||
:field-name="`secondaryDiagnosis[${idx}]`"
|
||||
:errors="errors"
|
||||
/>
|
||||
<Button type="button" variant="destructive" size="sm" @click="remove(idx)">
|
||||
<Icon name="i-lucide-trash-2" class="h-4 w-4" />
|
||||
<DE.Cell :col-span="2">
|
||||
<h1 class="mb-3 text-base font-medium">Diagnosa Sekunder</h1>
|
||||
<div class="w-full rounded-md border bg-gray-50/50 p-4 shadow-sm dark:bg-neutral-950">
|
||||
|
||||
<FieldArray v-slot="{ fields, push, remove }" name="secondaryDiagnosis">
|
||||
<div v-for="(field, idx) in fields" :key="idx" class="flex items-center gap-3 mb-3">
|
||||
<div class="w-full">
|
||||
<h1 class="font-medium">Diagnosa {{ idx + 1 }}</h1>
|
||||
<div class="flex gap-3">
|
||||
<InputBase
|
||||
:field-name="`secondaryDiagnosis[${idx}].diagnosis`"
|
||||
label="Diagnosa" placeholder="Masukkan Diagnosa"
|
||||
:errors="errors" is-required />
|
||||
<SelectIcd10
|
||||
:field-name="`secondaryDiagnosis[${idx}].icd10`"
|
||||
label="ICD 10"
|
||||
placeholder="ICD 10"
|
||||
:errors="errors" is-required />
|
||||
</div>
|
||||
<TextAreaInput :field-name="`secondaryDiagnosis[${idx}].diagnosisBasis`"
|
||||
label="Dasar Diagnosa" placeholder="Masukkan Dasar Diagnosa Pasien" :errors="errors" />
|
||||
</div>
|
||||
<Button v-if="idx !== 0" type="button" variant="destructive" size="sm" @click="remove(idx)">
|
||||
<Icon name="i-lucide-trash-2" class="h-4 w-4" />
|
||||
</Button>
|
||||
</div>
|
||||
<Button type="button" variant="outline"
|
||||
class="w-full rounded-md border border-primary bg-white px-4 py-2 text-primary hover:border-primary hover:bg-primary hover:text-white sm:w-auto sm:text-sm"
|
||||
@click="push(DEFAULT_SECONDARY_DIAGNOSIS_VALUE)">
|
||||
<Icon name="i-lucide-plus" class="mr-2 h-4 w-4 align-middle transition-colors" />
|
||||
Tambah Diagnosis
|
||||
</Button>
|
||||
</div>
|
||||
<Button type="button" variant="outline"
|
||||
class="w-full rounded-md border border-primary bg-white px-4 py-2 text-primary hover:border-primary hover:bg-primary hover:text-white sm:w-auto sm:text-sm"
|
||||
@click="push(``)">
|
||||
<Icon name="i-lucide-plus" class="mr-2 h-4 w-4 align-middle transition-colors" />
|
||||
Tambah Diagnosis
|
||||
</Button>
|
||||
</FieldArray>
|
||||
</div>
|
||||
</DE.Block>
|
||||
<Separator class="my-4" />
|
||||
</FieldArray>
|
||||
</div>
|
||||
</DE.Cell>
|
||||
|
||||
|
||||
<!-- DIAGNOSIS -->
|
||||
<h1 class="mb-3 text-base font-medium">Tindakan Operatif/Non Operatif</h1>
|
||||
<DE.Block class="w-3/5 space-y-2" :cell-flex="false">
|
||||
<SelectPrimaryDiagnosis
|
||||
field-name="primaryOperativeNonOperativeAct"
|
||||
label="Tindakan Operatif Utama"
|
||||
placeholder="Tindakan Operatif Utama"
|
||||
:errors="errors" is-required />
|
||||
|
||||
<div class="w-full rounded-md border bg-gray-50/50 p-4 shadow-sm dark:bg-neutral-950">
|
||||
<h1 class="mb-3 font-medium">Tindakan / Prosedur</h1>
|
||||
|
||||
<FieldArray v-slot="{ fields, push, remove }" name="secondaryOperativeNonOperativeAct">
|
||||
<div v-for="(field, idx) in fields" :key="idx" class="flex items-center gap-3 mb-3">
|
||||
<SelectSecondaryDiagnosis
|
||||
:field-name="`secondaryOperativeNonOperativeAct[${idx}]`"
|
||||
:errors="errors"
|
||||
/>
|
||||
<Button type="button" variant="destructive" size="sm" @click="remove(idx)">
|
||||
<Icon name="i-lucide-trash-2" class="h-4 w-4" />
|
||||
</Button>
|
||||
</div>
|
||||
<Button type="button" variant="outline"
|
||||
class="w-full rounded-md border border-primary bg-white px-4 py-2 text-primary hover:border-primary hover:bg-primary hover:text-white sm:w-auto sm:text-sm"
|
||||
@click="push(``)">
|
||||
<Icon name="i-lucide-plus" class="mr-2 h-4 w-4 align-middle transition-colors" />
|
||||
Tambah Tindakan / Prosedur
|
||||
</Button>
|
||||
</FieldArray>
|
||||
</div>
|
||||
</DE.Block>
|
||||
<Separator class="my-4" />
|
||||
|
||||
<DE.Block class="w-3/5" :cell-flex="false">
|
||||
<TextAreaInput field-name="medikamentosa" label="Medikamentosa" placeholder="Medikamentosa" :errors="errors" />
|
||||
</DE.Block>
|
||||
<Separator class="my-4" />
|
||||
|
||||
<h1 class="mb-3 font-medium">Penatalaksanaan</h1>
|
||||
<DE.Block :col-count="3" :cell-flex="false">
|
||||
<SelectArrangement field-name="arrangement" label="Lanjutan Penatalaksanaan" placeholder="Pilih Arrangement" :errors="errors" />
|
||||
|
||||
</DE.Block>
|
||||
<Separator class="my-4" />
|
||||
|
||||
|
||||
|
||||
|
||||
<!-- Tindakan OPERATIF/NON OPERATIF -->
|
||||
<div class="mb-3 flex gap-3 items-center">
|
||||
<h1 class="text-base font-medium">Tindakan Operatif/Non Operatif</h1>
|
||||
<Button variant="ghost"
|
||||
class="gap-1 items-center text-orange-400"
|
||||
@click="isActionHistoryOpen = true">
|
||||
<Icon name="i-lucide-history" class="h-4 w-4" /> Riwayat Tindakan</Button>
|
||||
</div>
|
||||
<h1 class="mb-3 font-normal">Tindakan Operatif/Non Operatif Utama</h1>
|
||||
<DE.Block :col-count="2" class="" :cell-flex="false">
|
||||
<InputBase
|
||||
field-name="diagnosis"
|
||||
label="Tindakan" placeholder="Masukkan Tindakan"
|
||||
:errors="errors" is-required />
|
||||
<SelectIcd9
|
||||
field-name="primaryDiagnosis"
|
||||
label="ICD 9"
|
||||
placeholder="ICD 9"
|
||||
:errors="errors" is-required />
|
||||
<DE.Cell :col-span="2">
|
||||
<TextAreaInput field-name="supplementCheckup"
|
||||
label="Dasar Tindakan" placeholder="Masukkan Dasar Tindakan utama Pasien" :errors="errors" />
|
||||
</DE.Cell>
|
||||
|
||||
<DE.Cell :col-span="2">
|
||||
<h1 class="mb-3 text-base font-medium">Tindakan Lain</h1>
|
||||
<div class="w-full rounded-md border bg-gray-50/50 p-4 shadow-sm dark:bg-neutral-950">
|
||||
|
||||
<FieldArray v-slot="{ fields, push, remove }" name="secondaryOperativeNonOperativeAct">
|
||||
<div v-for="(field, idx) in fields" :key="idx" class="flex items-center gap-3 mb-3">
|
||||
<div class="w-full">
|
||||
<h1 class="font-medium">Tindakan {{ idx + 1 }}</h1>
|
||||
<div class="flex gap-3">
|
||||
<InputBase
|
||||
:field-name="`secondaryOperativeNonOperativeAct[${idx}].action`"
|
||||
label="Tindakan" placeholder="Masukkan Tindakan"
|
||||
:errors="errors" is-required />
|
||||
<SelectIcd10
|
||||
:field-name="`secondaryOperativeNonOperativeAct[${idx}].icd9`"
|
||||
label="ICD 10"
|
||||
placeholder="ICD 10"
|
||||
:errors="errors" is-required />
|
||||
</div>
|
||||
<TextAreaInput :field-name="`secondaryOperativeNonOperativeAct[${idx}].actionBasis`"
|
||||
label="Dasar Tindakan" placeholder="Masukkan Dasar Tindakan Pasien" :errors="errors" />
|
||||
</div>
|
||||
<Button v-if="idx !== 0" type="button" variant="destructive" size="sm" @click="remove(idx)">
|
||||
<Icon name="i-lucide-trash-2" class="h-4 w-4" />
|
||||
</Button>
|
||||
</div>
|
||||
<Button type="button" variant="outline"
|
||||
class="w-full rounded-md border border-primary bg-white px-4 py-2 text-primary hover:border-primary hover:bg-primary hover:text-white sm:w-auto sm:text-sm"
|
||||
@click="push(DEFAULT_SECONDARY_ACTION_VALUE)">
|
||||
<Icon name="i-lucide-plus" class="mr-2 h-4 w-4 align-middle transition-colors" />
|
||||
Tambah Tindakan
|
||||
</Button>
|
||||
</FieldArray>
|
||||
</div>
|
||||
</DE.Cell>
|
||||
|
||||
</DE.Block>
|
||||
<TextAreaInput :field-name="`medicalAction`"
|
||||
label="Tindakan Medis" placeholder="Masukkan Tindakan Medis" :errors="errors" />
|
||||
<Separator class="my-4" />
|
||||
|
||||
|
||||
|
||||
<!-- KONSULTASI -->
|
||||
<div class="mb-3 flex gap-3 items-center">
|
||||
<h1 class="text-base font-medium">Konsultasi</h1>
|
||||
<Button variant="ghost"
|
||||
class="gap-1 items-center text-orange-400"
|
||||
@click="isConsultationHistoryOpen = true">
|
||||
<Icon name="i-lucide-history" class="h-4 w-4" /> Riwayat Konsultasi</Button>
|
||||
</div>
|
||||
<div class="w-full rounded-md border bg-gray-50/50 p-4 shadow-sm dark:bg-neutral-950">
|
||||
<FieldArray v-slot="{ fields, push, remove }" name="consultation">
|
||||
<div v-for="(field, idx) in fields" :key="idx" class="flex items-center gap-3 mb-3">
|
||||
<div class="w-full">
|
||||
<h1 class="font-medium mb-1">Konsultasi {{ idx + 1 }}</h1>
|
||||
<div class="flex gap-3">
|
||||
<TextAreaInput :field-name="`consultation[${idx}].consultation`"
|
||||
label="Konsultasi" placeholder="Masukkan Konsultasi" :errors="errors" />
|
||||
<TextAreaInput :field-name="`consultation[${idx}].consultationReply`"
|
||||
label="Jawaban Konsultasi" placeholder="Masukkan Jawaban Konsultasi" :errors="errors" />
|
||||
</div>
|
||||
</div>
|
||||
<Button v-if="idx !== 0" type="button" variant="destructive" size="sm" @click="remove(idx)">
|
||||
<Icon name="i-lucide-trash-2" class="h-4 w-4" />
|
||||
</Button>
|
||||
</div>
|
||||
<Button type="button" variant="outline"
|
||||
class="w-full rounded-md border border-primary bg-white px-4 py-2 text-primary hover:border-primary hover:bg-primary hover:text-white sm:w-auto sm:text-sm"
|
||||
@click="push(DEFAULT_CONSULTATION_VALUE)">
|
||||
<Icon name="i-lucide-plus" class="mr-2 h-4 w-4 align-middle transition-colors" />
|
||||
Tambah Konsultasi
|
||||
</Button>
|
||||
</FieldArray>
|
||||
</div>
|
||||
<Separator class="my-4" />
|
||||
|
||||
|
||||
|
||||
<!-- DATA PENUNJANG -->
|
||||
<section>
|
||||
<div class="mb-3 flex gap-3 items-center">
|
||||
<h1 class="text-base font-medium">Data Penunjang</h1>
|
||||
<Button variant="ghost"
|
||||
class="gap-1 items-center text-orange-400"
|
||||
@click="isSupportingHistoryOpen = true">
|
||||
<Icon name="i-lucide-history" class="h-4 w-4" /> Riwayat Data Penunjang</Button>
|
||||
</div>
|
||||
<DE.Block class="" :cell-flex="false">
|
||||
<TextAreaInput field-name="supplementCheckup" label="Pemeriksaan Penunjang" placeholder="Masukkan Pemeriksaan Penunjang" :errors="errors" />
|
||||
</DE.Block>
|
||||
</section>
|
||||
<Separator class="my-4" />
|
||||
|
||||
|
||||
|
||||
<!-- DATA Farmasi -->
|
||||
<section>
|
||||
<div class="mb-3 flex gap-3 items-center">
|
||||
<h1 class="text-base font-medium">Data Farmasi</h1>
|
||||
<Button variant="ghost"
|
||||
class="gap-1 items-center text-orange-400"
|
||||
@click="isFarmacyHistoryOpen = true">
|
||||
<Icon name="i-lucide-history" class="h-4 w-4" /> Riwayat Data Farmasi</Button>
|
||||
</div>
|
||||
<DE.Block class="items-end" :col-count="3" :cell-flex="false">
|
||||
<TextAreaInput field-name="supplementCheckup"
|
||||
label="Kelainan Khusus Alergi" placeholder="Masukkan Kelainan Khusus Alergi" :errors="errors" />
|
||||
<TextAreaInput field-name="supplementCheckup"
|
||||
label="Kelainan Lain" placeholder="Masukkan Kelainan Lain" :errors="errors" />
|
||||
<TextAreaInput field-name="supplementCheckup"
|
||||
label="Terapi yang Diberikan (Farmakologi dan Non Farmakologi) Selama Dirawat" placeholder="Masukkan Terapi yang Diberikan (Farmakologi dan Non Farmakologi) Selama Dirawat" :errors="errors" />
|
||||
<TextAreaInput field-name="supplementCheckup"
|
||||
label="Terapi yang Diberikan (Farmakologi dan Non Farmakologi) Waktu Pulang" placeholder="Masukkan Terapi yang Diberikan (Farmakologi dan Non Farmakologi) Waktu Pulang" :errors="errors" />
|
||||
<TextAreaInput field-name="supplementCheckup"
|
||||
label="Instruksi Tindak Lanjut/Anjuran dan Edukasi (Follow Up/Kontrol)" placeholder="Masukkan Instruksi Tindak Lanjut/Anjuran dan Edukasi (Follow Up/Kontrol)" :errors="errors" />
|
||||
</DE.Block>
|
||||
</section>
|
||||
<Separator class="my-4" />
|
||||
|
||||
|
||||
|
||||
<!-- Keadaan Waktu Keluar -->
|
||||
<section>
|
||||
<h1 class="mb-3 font-medium">Keadaan Waktu Keluar</h1>
|
||||
<DE.Block :col-count="4" :cell-flex="false">
|
||||
<InputBase
|
||||
:field-name="`aaaaaaaaaaa`"
|
||||
label="Tekanan Darah Sistol" placeholder="Masukkan Tekanan Darah Sistol"
|
||||
right-label="mmHg" bottom-label="Contoh: 90"
|
||||
:errors="errors" is-required numeric-only />
|
||||
<InputBase
|
||||
:field-name="`aaaaaaaaaaa`"
|
||||
label="Tekanan Darah Diastol" placeholder="Masukkan Tekanan Darah Diastol"
|
||||
right-label="mmHg" bottom-label="Contoh: 60"
|
||||
:errors="errors" is-required numeric-only />
|
||||
<InputBase
|
||||
:field-name="`aaaaaaaaaaa`"
|
||||
label="Pernafasan" placeholder="Masukkan Pernafasan"
|
||||
right-label="kali / menit" bottom-label="Contoh: 20"
|
||||
:errors="errors" is-required numeric-only />
|
||||
<InputBase
|
||||
:field-name="`aaaaaaaaaaa`"
|
||||
label="Denyut Jantung" placeholder="Masukkan Denyut Jantung"
|
||||
right-label="kali / menit" bottom-label="Contoh: 20"
|
||||
:errors="errors" is-required numeric-only />
|
||||
<InputBase
|
||||
:field-name="`aaaaaaaaaaa`"
|
||||
label="Suhu Tubuh" placeholder="Masukkan Suhu Tubuh"
|
||||
right-label="'C" bottom-label="Contoh: 37"
|
||||
:errors="errors" is-required numeric-only />
|
||||
<SelectConciousLevel
|
||||
:field-name="`aaaaaaaaaaa`"
|
||||
label="Tingkat Kesadaran"
|
||||
placeholder="Tingkat Kesadaran"
|
||||
:errors="errors" is-required />
|
||||
<SelectPainScale
|
||||
:field-name="`aaaaaaaaaaa`"
|
||||
label="Skala Nyeri"
|
||||
placeholder="Skala Nyeri"
|
||||
:errors="errors" is-required />
|
||||
</DE.Block>
|
||||
</section>
|
||||
<Separator class="my-4" />
|
||||
|
||||
|
||||
|
||||
<!-- Program Nasional -->
|
||||
<section>
|
||||
<div class="mb-3 flex gap-3 items-center">
|
||||
<h1 class="text-base font-medium">Program Nasional</h1>
|
||||
<Button variant="ghost"
|
||||
class="gap-1 items-center text-orange-400"
|
||||
@click="isNationalProgramServiceHistoryOpen = true">
|
||||
<Icon name="i-lucide-history" class="h-4 w-4" /> Riwayat Program Nasional</Button>
|
||||
</div>
|
||||
<DE.Block :col-count="3" :cell-flex="false">
|
||||
<SelectNationalProgramService
|
||||
:field-name="`aaaaaaaaaaa`"
|
||||
label="Layanan Program Nasional"
|
||||
placeholder="Layanan Program Nasional"
|
||||
:errors="errors" is-required />
|
||||
<SelectNationalProgramServiceStatus
|
||||
:field-name="`aaaaaaaaaaa`"
|
||||
label="Status Layanan Program Nasional"
|
||||
placeholder="Status Layanan Program Nasional"
|
||||
:errors="errors" is-required />
|
||||
</DE.Block>
|
||||
</section>
|
||||
<Separator class="my-4" />
|
||||
|
||||
|
||||
|
||||
<!-- Penatalaksanaan -->
|
||||
<section>
|
||||
<h1 class="mb-3 font-medium">Penatalaksanaan</h1>
|
||||
<DE.Block :col-count="3" :cell-flex="false">
|
||||
<SelectArrangement
|
||||
field-name="arrangement"
|
||||
label="Lanjutan Penatalaksanaan"
|
||||
placeholder="Pilih Arrangement"
|
||||
:errors="errors" />
|
||||
<SelectHospitalLeaveCondition
|
||||
:field-name="`aaaaaaaaaaa`"
|
||||
label="Kondisi Meninggalkan RS"
|
||||
placeholder="Kondisi Meninggalkan RS"
|
||||
:errors="errors" is-required />
|
||||
<SelectHospitalLeaveMethod
|
||||
:field-name="`aaaaaaaaaaa`"
|
||||
label="Cara Keluar RS"
|
||||
placeholder="Cara Keluar RS"
|
||||
:errors="errors" is-required />
|
||||
</DE.Block>
|
||||
</section>
|
||||
|
||||
<DE.Block :col-count="3" :cell-flex="false">
|
||||
<SelectFaskes
|
||||
v-show="resumeArrangementType === `rujuk` || resumeArrangementType === `rujukBalik` "
|
||||
field-name="faskes"
|
||||
@@ -148,8 +428,8 @@ defineExpose({
|
||||
:errors="errors"
|
||||
:is-with-time="true" />
|
||||
|
||||
<DE.Cell class="mt-2" :col-span="2" v-show="resumeArrangementType === `meninggal`">
|
||||
<div class="w-full rounded-md border bg-gray-50/50 p-4 shadow-sm dark:bg-neutral-950">
|
||||
<DE.Cell class="mt-2" :col-span="3" v-show="resumeArrangementType === `meninggal`">
|
||||
<div class="w-2/3 rounded-md border bg-gray-50/50 p-4 shadow-sm dark:bg-neutral-950">
|
||||
<h1 class="mb-3 font-medium">Sebab Meninggal</h1>
|
||||
|
||||
<FieldArray v-slot="{ fields, push, remove }" name="deathCause">
|
||||
@@ -158,11 +438,11 @@ defineExpose({
|
||||
:field-name="`deathCause[${idx}]`"
|
||||
:errors="errors"
|
||||
/>
|
||||
<Button type="button" variant="destructive" size="sm" @click="remove(idx)">
|
||||
<Button v-if="idx !== 0" type="button" variant="destructive" size="sm" @click="remove(idx)">
|
||||
<Icon name="i-lucide-trash-2" class="h-4 w-4" />
|
||||
</Button>
|
||||
</div>
|
||||
<Button type="button" variant="outline"
|
||||
<Button v-if="fields.length < 3" type="button" variant="outline"
|
||||
class="w-full rounded-md border border-primary bg-white px-4 py-2 text-primary hover:border-primary hover:bg-primary hover:text-white sm:w-auto sm:text-sm"
|
||||
@click="push(``)">
|
||||
<Icon name="i-lucide-plus" class="mr-2 h-4 w-4 align-middle transition-colors" />
|
||||
@@ -172,12 +452,24 @@ defineExpose({
|
||||
</div>
|
||||
</DE.Cell>
|
||||
|
||||
<TextAreaInput
|
||||
v-show="resumeArrangementType === `other`"
|
||||
field-name="keterangan"
|
||||
label="Keterangan"
|
||||
placeholder="Keterangan"
|
||||
:errors="errors" />
|
||||
<DE.Cell
|
||||
v-show="resumeArrangementType === `meninggal`"
|
||||
:col-span="3">
|
||||
<TextAreaInput
|
||||
field-name="deathCauseDescription"
|
||||
label="Keterangan Sebab Meninggal"
|
||||
placeholder="Keterangan Sebab Meninggal"
|
||||
:errors="errors" />
|
||||
</DE.Cell>
|
||||
|
||||
<DE.Cell :col-span="3"
|
||||
v-show="resumeArrangementType === `other`">
|
||||
<TextAreaInput
|
||||
field-name="keterangan"
|
||||
label="Keterangan"
|
||||
placeholder="Keterangan"
|
||||
:errors="errors" />
|
||||
</DE.Cell>
|
||||
|
||||
</DE.Block>
|
||||
|
||||
|
||||
@@ -0,0 +1,66 @@
|
||||
<script setup lang="ts">
|
||||
import Dialog from '~/components/pub/my-ui/modal/dialog.vue'
|
||||
import type { PaginationMeta } from '~/components/pub/my-ui/pagination/pagination.type'
|
||||
import PaginationView from '~/components/pub/my-ui/pagination/pagination-view.vue'
|
||||
import { config } from './action-list.cfg'
|
||||
import { cn } from '~/lib/utils'
|
||||
import { CalendarDate, DateFormatter, getLocalTimeZone } from '@internationalized/date'
|
||||
import type { DateRange } from 'radix-vue'
|
||||
import { CalendarIcon } from 'lucide-vue-next'
|
||||
|
||||
interface Props {
|
||||
data: any[]
|
||||
paginationMeta: PaginationMeta
|
||||
dateValue: DateRange
|
||||
}
|
||||
const props = defineProps<Props>()
|
||||
const isModalOpen = inject(`isActionHistoryOpen`) as Ref<boolean>
|
||||
|
||||
const df = new DateFormatter('en-US', { dateStyle: 'medium',})
|
||||
|
||||
const emit = defineEmits<{
|
||||
pageChange: [page: number]
|
||||
'update:dateValue': [value: DateRange]
|
||||
}>()
|
||||
|
||||
function handlePageChange(page: number) {
|
||||
emit('pageChange', page)
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Dialog v-model:open="isModalOpen" title="" size="2xl">
|
||||
<div class="space-y-4">
|
||||
<Popover>
|
||||
<PopoverTrigger as-child>
|
||||
<Button variant="outline" :class="cn('mb-1 w-[280px] justify-start text-left font-normal',
|
||||
!props.dateValue && 'text-muted-foreground')">
|
||||
<CalendarIcon class="mr-2 h-4 w-4" />
|
||||
<template v-if="props.dateValue.start">
|
||||
<template v-if="props.dateValue.end">
|
||||
{{ df.format(props.dateValue.start.toDate(getLocalTimeZone())) }} -
|
||||
{{ df.format(props.dateValue.end.toDate(getLocalTimeZone())) }}
|
||||
</template>
|
||||
|
||||
<template v-else>
|
||||
{{ df.format(props.dateValue.start.toDate(getLocalTimeZone())) }}
|
||||
</template>
|
||||
</template>
|
||||
<template v-else> Pick a date </template>
|
||||
</Button>
|
||||
</PopoverTrigger>
|
||||
<PopoverContent class="w-auto p-0">
|
||||
<RangeCalendar v-model="props.dateValue" initial-focus :number-of-months="2"
|
||||
@update:model-value="(date) => emit('update:dateValue', date)" />
|
||||
</PopoverContent>
|
||||
</Popover>
|
||||
|
||||
<PubMyUiDataTable
|
||||
v-bind="config"
|
||||
:rows="data"
|
||||
:skeleton-size="props.paginationMeta?.pageSize"
|
||||
/>
|
||||
<PaginationView :pagination-meta="props.paginationMeta" @page-change="handlePageChange" />
|
||||
</div>
|
||||
</Dialog>
|
||||
</template>
|
||||
@@ -0,0 +1,94 @@
|
||||
import type { Config } from '~/components/pub/my-ui/data-table'
|
||||
import type { Patient } from '~/models/patient'
|
||||
import { defineAsyncComponent } from 'vue'
|
||||
import { educationCodes, genderCodes } from '~/lib/constants'
|
||||
import { calculateAge } from '~/lib/utils'
|
||||
|
||||
const action = defineAsyncComponent(() => import('~/components/pub/my-ui/data/dropdown-action-dvvp.vue'))
|
||||
|
||||
export const config: Config = {
|
||||
cols: [{width: 140}, {}, {}, {width: 140}, {width: 10},],
|
||||
|
||||
headers: [
|
||||
[
|
||||
{ label: 'Tanggal/Jam' },
|
||||
{ label: 'Dokter' },
|
||||
{ label: 'Tempat Layanan' },
|
||||
{ label: 'Jenis' },
|
||||
{ label: 'Jenis Pemeriksaan' },
|
||||
{ label: 'Tanggal/Jam' },
|
||||
],
|
||||
],
|
||||
|
||||
keys: ['birth_date', 'person.name', 'person.name', 'person.name', 'person.name', 'birth_date',],
|
||||
|
||||
delKeyNames: [
|
||||
{ key: 'code', label: 'Kode' },
|
||||
{ key: 'name', label: 'Nama' },
|
||||
],
|
||||
|
||||
parses: {
|
||||
patientId: (rec: unknown): unknown => {
|
||||
const patient = rec as Patient
|
||||
return patient.number
|
||||
},
|
||||
identity_number: (rec: unknown): unknown => {
|
||||
const { person } = rec as Patient
|
||||
|
||||
if (person.nationality == 'WNA') {
|
||||
return person.passportNumber
|
||||
}
|
||||
|
||||
return person.residentIdentityNumber || '-'
|
||||
},
|
||||
birth_date: (rec: unknown): unknown => {
|
||||
const { person } = rec as Patient
|
||||
|
||||
if (typeof person.birthDate == 'object' && person.birthDate) {
|
||||
return (person.birthDate as Date).toLocaleDateString('id-ID')
|
||||
} else if (typeof person.birthDate == 'string') {
|
||||
return (person.birthDate as string).substring(0, 10)
|
||||
}
|
||||
return person.birthDate
|
||||
},
|
||||
patient_age: (rec: unknown): unknown => {
|
||||
const { person } = rec as Patient
|
||||
return calculateAge(person.birthDate)
|
||||
},
|
||||
gender: (rec: unknown): unknown => {
|
||||
const { person } = rec as Patient
|
||||
|
||||
if (typeof person.gender_code == 'number' && person.gender_code >= 0) {
|
||||
return person.gender_code
|
||||
} else if (typeof person.gender_code === 'string' && person.gender_code) {
|
||||
return genderCodes[person.gender_code] || '-'
|
||||
}
|
||||
return '-'
|
||||
},
|
||||
education: (rec: unknown): unknown => {
|
||||
const { person } = rec as Patient
|
||||
if (typeof person.education_code == 'number' && person.education_code >= 0) {
|
||||
return person.education_code
|
||||
} else if (typeof person.education_code === 'string' && person.education_code) {
|
||||
return educationCodes[person.education_code] || '-'
|
||||
}
|
||||
return '-'
|
||||
},
|
||||
},
|
||||
|
||||
components: {
|
||||
action(rec, idx) {
|
||||
return {
|
||||
idx,
|
||||
rec: rec as object,
|
||||
component: action,
|
||||
}
|
||||
},
|
||||
},
|
||||
|
||||
htmls: {
|
||||
patient_address(_rec) {
|
||||
return '-'
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
<script setup lang="ts">
|
||||
import Dialog from '~/components/pub/my-ui/modal/dialog.vue'
|
||||
import type { PaginationMeta } from '~/components/pub/my-ui/pagination/pagination.type'
|
||||
import PaginationView from '~/components/pub/my-ui/pagination/pagination-view.vue'
|
||||
import { config } from './consultation-list.cfg'
|
||||
import { cn } from '~/lib/utils'
|
||||
import { CalendarDate, DateFormatter, getLocalTimeZone } from '@internationalized/date'
|
||||
import type { DateRange } from 'radix-vue'
|
||||
import { CalendarIcon } from 'lucide-vue-next'
|
||||
|
||||
interface Props {
|
||||
data: any[]
|
||||
paginationMeta: PaginationMeta
|
||||
dateValue: DateRange
|
||||
}
|
||||
const props = defineProps<Props>()
|
||||
const isModalOpen = inject(`isConsultationHistoryOpen`) as Ref<boolean>
|
||||
|
||||
const df = new DateFormatter('en-US', { dateStyle: 'medium',})
|
||||
|
||||
const emit = defineEmits<{
|
||||
pageChange: [page: number]
|
||||
'update:dateValue': [value: DateRange]
|
||||
}>()
|
||||
|
||||
function handlePageChange(page: number) {
|
||||
emit('pageChange', page)
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Dialog v-model:open="isModalOpen" title="" size="2xl">
|
||||
<div class="space-y-4">
|
||||
<Popover>
|
||||
<PopoverTrigger as-child>
|
||||
<Button variant="outline" :class="cn('mb-1 w-[280px] justify-start text-left font-normal',
|
||||
!props.dateValue && 'text-muted-foreground')">
|
||||
<CalendarIcon class="mr-2 h-4 w-4" />
|
||||
<template v-if="props.dateValue.start">
|
||||
<template v-if="props.dateValue.end">
|
||||
{{ df.format(props.dateValue.start.toDate(getLocalTimeZone())) }} -
|
||||
{{ df.format(props.dateValue.end.toDate(getLocalTimeZone())) }}
|
||||
</template>
|
||||
|
||||
<template v-else>
|
||||
{{ df.format(props.dateValue.start.toDate(getLocalTimeZone())) }}
|
||||
</template>
|
||||
</template>
|
||||
<template v-else> Pick a date </template>
|
||||
</Button>
|
||||
</PopoverTrigger>
|
||||
<PopoverContent class="w-auto p-0">
|
||||
<RangeCalendar v-model="props.dateValue" initial-focus :number-of-months="2"
|
||||
@update:model-value="(date) => emit('update:dateValue', date)" />
|
||||
</PopoverContent>
|
||||
</Popover>
|
||||
|
||||
<PubMyUiDataTable
|
||||
v-bind="config"
|
||||
:rows="data"
|
||||
:skeleton-size="props.paginationMeta?.pageSize"
|
||||
/>
|
||||
<PaginationView :pagination-meta="props.paginationMeta" @page-change="handlePageChange" />
|
||||
</div>
|
||||
</Dialog>
|
||||
</template>
|
||||
@@ -0,0 +1,51 @@
|
||||
import type { Config } from '~/components/pub/my-ui/data-table'
|
||||
import type { Patient } from '~/models/patient'
|
||||
import { defineAsyncComponent } from 'vue'
|
||||
|
||||
const lampiranBtn = defineAsyncComponent(() => import('../_common/print-btn.vue'))
|
||||
|
||||
export const config: Config = {
|
||||
cols: [{}, {}, {}, {}, {},],
|
||||
|
||||
headers: [
|
||||
[
|
||||
{ label: 'Tanggal/Jam' },
|
||||
{ label: 'Dokter' },
|
||||
{ label: 'Tempat Layanan' },
|
||||
{ label: 'KSM' },
|
||||
{ label: 'Tanggal/Jam' },
|
||||
{ label: 'Tujuan' },
|
||||
{ label: 'Dokter' },
|
||||
{ label: 'Berkas' },
|
||||
],
|
||||
],
|
||||
|
||||
keys: ['birth_date', 'person.name', 'person.name', 'person.name', 'person.name', 'birth_date','person.name', 'action', ],
|
||||
|
||||
parses: {
|
||||
birth_date: (rec: unknown): unknown => {
|
||||
const { person } = rec as Patient
|
||||
|
||||
if (typeof person.birthDate == 'object' && person.birthDate) {
|
||||
return (person.birthDate as Date).toLocaleDateString('id-ID')
|
||||
} else if (typeof person.birthDate == 'string') {
|
||||
return (person.birthDate as string).substring(0, 10)
|
||||
}
|
||||
return person.birthDate
|
||||
},
|
||||
},
|
||||
|
||||
components: {
|
||||
action(rec, idx) {
|
||||
return {
|
||||
idx,
|
||||
rec: rec as object,
|
||||
component: lampiranBtn,
|
||||
}
|
||||
},
|
||||
},
|
||||
|
||||
htmls: {
|
||||
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
<script setup lang="ts">
|
||||
import Dialog from '~/components/pub/my-ui/modal/dialog.vue'
|
||||
import type { PaginationMeta } from '~/components/pub/my-ui/pagination/pagination.type'
|
||||
import PaginationView from '~/components/pub/my-ui/pagination/pagination-view.vue'
|
||||
import { config } from './farmacy-list.cfg'
|
||||
import { cn } from '~/lib/utils'
|
||||
import { CalendarDate, DateFormatter, getLocalTimeZone } from '@internationalized/date'
|
||||
import type { DateRange } from 'radix-vue'
|
||||
import { CalendarIcon } from 'lucide-vue-next'
|
||||
|
||||
interface Props {
|
||||
data: any[]
|
||||
paginationMeta: PaginationMeta
|
||||
dateValue: DateRange
|
||||
}
|
||||
const props = defineProps<Props>()
|
||||
const isModalOpen = inject(`isFarmacyHistoryOpen`) as Ref<boolean>
|
||||
|
||||
const df = new DateFormatter('en-US', { dateStyle: 'medium',})
|
||||
|
||||
const emit = defineEmits<{
|
||||
pageChange: [page: number]
|
||||
'update:dateValue': [value: DateRange]
|
||||
}>()
|
||||
|
||||
function handlePageChange(page: number) {
|
||||
emit('pageChange', page)
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Dialog v-model:open="isModalOpen" title="" size="2xl">
|
||||
<div class="space-y-4">
|
||||
<Popover>
|
||||
<PopoverTrigger as-child>
|
||||
<Button variant="outline" :class="cn('mb-1 w-[280px] justify-start text-left font-normal',
|
||||
!props.dateValue && 'text-muted-foreground')">
|
||||
<CalendarIcon class="mr-2 h-4 w-4" />
|
||||
<template v-if="props.dateValue.start">
|
||||
<template v-if="props.dateValue.end">
|
||||
{{ df.format(props.dateValue.start.toDate(getLocalTimeZone())) }} -
|
||||
{{ df.format(props.dateValue.end.toDate(getLocalTimeZone())) }}
|
||||
</template>
|
||||
|
||||
<template v-else>
|
||||
{{ df.format(props.dateValue.start.toDate(getLocalTimeZone())) }}
|
||||
</template>
|
||||
</template>
|
||||
<template v-else> Pick a date </template>
|
||||
</Button>
|
||||
</PopoverTrigger>
|
||||
<PopoverContent class="w-auto p-0">
|
||||
<RangeCalendar v-model="props.dateValue" initial-focus :number-of-months="2"
|
||||
@update:model-value="(date) => emit('update:dateValue', date)" />
|
||||
</PopoverContent>
|
||||
</Popover>
|
||||
|
||||
<PubMyUiDataTable
|
||||
v-bind="config"
|
||||
:rows="data"
|
||||
:skeleton-size="props.paginationMeta?.pageSize"
|
||||
/>
|
||||
<PaginationView :pagination-meta="props.paginationMeta" @page-change="handlePageChange" />
|
||||
</div>
|
||||
</Dialog>
|
||||
</template>
|
||||
@@ -0,0 +1,39 @@
|
||||
import type { Config } from '~/components/pub/my-ui/data-table'
|
||||
import type { Patient } from '~/models/patient'
|
||||
|
||||
export const config: Config = {
|
||||
cols: [{}, {}, {}, {}, {},],
|
||||
|
||||
headers: [
|
||||
[
|
||||
{ label: 'Tanggal Order' },
|
||||
{ label: 'No Resep' },
|
||||
{ label: 'Tempat Layanan' },
|
||||
{ label: 'Nama Obat' },
|
||||
{ label: 'Tanggal Disetujui' },
|
||||
],
|
||||
],
|
||||
|
||||
keys: ['birth_date', 'person.name', 'person.name', 'person.name', 'birth_date',],
|
||||
|
||||
parses: {
|
||||
birth_date: (rec: unknown): unknown => {
|
||||
const { person } = rec as Patient
|
||||
|
||||
if (typeof person.birthDate == 'object' && person.birthDate) {
|
||||
return (person.birthDate as Date).toLocaleDateString('id-ID')
|
||||
} else if (typeof person.birthDate == 'string') {
|
||||
return (person.birthDate as string).substring(0, 10)
|
||||
}
|
||||
return person.birthDate
|
||||
},
|
||||
},
|
||||
|
||||
components: {
|
||||
|
||||
},
|
||||
|
||||
htmls: {
|
||||
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
<script setup lang="ts">
|
||||
import Dialog from '~/components/pub/my-ui/modal/dialog.vue'
|
||||
import type { PaginationMeta } from '~/components/pub/my-ui/pagination/pagination.type'
|
||||
import PaginationView from '~/components/pub/my-ui/pagination/pagination-view.vue'
|
||||
import { config } from './national-program-list.cfg'
|
||||
import { cn } from '~/lib/utils'
|
||||
import { CalendarDate, DateFormatter, getLocalTimeZone } from '@internationalized/date'
|
||||
import type { DateRange } from 'radix-vue'
|
||||
import { CalendarIcon } from 'lucide-vue-next'
|
||||
import type { Item } from '~/components/pub/my-ui/combobox'
|
||||
import Select from '~/components/pub/my-ui/form/select.vue'
|
||||
import * as DE from '~/components/pub/my-ui/doc-entry'
|
||||
|
||||
interface Props {
|
||||
data: any[]
|
||||
paginationMeta: PaginationMeta
|
||||
searchValue: string
|
||||
statusValue: string
|
||||
}
|
||||
const props = defineProps<Props>()
|
||||
const isModalOpen = inject(`isNationalProgramServiceHistoryOpen`) as Ref<boolean>
|
||||
|
||||
const emit = defineEmits<{
|
||||
pageChange: [page: number]
|
||||
'update:searchValue': [value: string]
|
||||
'update:statusValue': [value: string]
|
||||
}>()
|
||||
|
||||
function handlePageChange(page: number) {
|
||||
emit('pageChange', page)
|
||||
}
|
||||
|
||||
const statusOptions: Item[] = [
|
||||
{ value: 'all', label: 'All Statuses' },
|
||||
{ value: 'pending', label: 'Pending' },
|
||||
{ value: 'active', label: 'Active' },
|
||||
{ value: 'completed', label: 'Completed' },
|
||||
{ value: 'archived', label: 'Archived' },
|
||||
]
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Dialog v-model:open="isModalOpen" title="" size="2xl">
|
||||
<div class="space-y-4">
|
||||
<DE.Block :col-count="4" class="" :cell-flex="false">
|
||||
<Input
|
||||
v-model="props.searchValue"
|
||||
class=""
|
||||
placeholder="Cari .."/>
|
||||
<Select
|
||||
:items="statusOptions"
|
||||
:model-value="props.statusValue"
|
||||
@update:model-value="(data) => emit('update:statusValue', data)"
|
||||
/>
|
||||
</DE.Block>
|
||||
|
||||
<PubMyUiDataTable
|
||||
v-bind="config"
|
||||
:rows="data"
|
||||
:skeleton-size="props.paginationMeta?.pageSize"
|
||||
/>
|
||||
<PaginationView :pagination-meta="props.paginationMeta" @page-change="handlePageChange" />
|
||||
</div>
|
||||
</Dialog>
|
||||
</template>
|
||||
@@ -0,0 +1,30 @@
|
||||
import type { Config } from '~/components/pub/my-ui/data-table'
|
||||
import type { Patient } from '~/models/patient'
|
||||
|
||||
export const config: Config = {
|
||||
cols: [{}, {}, {}, {}, {},],
|
||||
|
||||
headers: [
|
||||
[
|
||||
{ label: 'Nomor' },
|
||||
{ label: 'Layanan Program Nasional' },
|
||||
{ label: 'Status' },
|
||||
],
|
||||
],
|
||||
|
||||
keys: ['person.name', 'person.name', 'person.name',],
|
||||
|
||||
parses: {
|
||||
// birth_date: (rec: unknown): unknown => {
|
||||
|
||||
// },
|
||||
},
|
||||
|
||||
components: {
|
||||
|
||||
},
|
||||
|
||||
htmls: {
|
||||
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
<script setup lang="ts">
|
||||
import Dialog from '~/components/pub/my-ui/modal/dialog.vue'
|
||||
import type { PaginationMeta } from '~/components/pub/my-ui/pagination/pagination.type'
|
||||
import PaginationView from '~/components/pub/my-ui/pagination/pagination-view.vue'
|
||||
import { config } from './supporting-list.cfg'
|
||||
import { cn } from '~/lib/utils'
|
||||
import { CalendarDate, DateFormatter, getLocalTimeZone } from '@internationalized/date'
|
||||
import type { DateRange } from 'radix-vue'
|
||||
import { CalendarIcon } from 'lucide-vue-next'
|
||||
|
||||
interface Props {
|
||||
data: any[]
|
||||
paginationMeta: PaginationMeta
|
||||
dateValue: DateRange
|
||||
}
|
||||
const props = defineProps<Props>()
|
||||
const isModalOpen = inject(`isSupportingHistoryOpen`) as Ref<boolean>
|
||||
|
||||
const df = new DateFormatter('en-US', { dateStyle: 'medium',})
|
||||
|
||||
const emit = defineEmits<{
|
||||
pageChange: [page: number]
|
||||
'update:dateValue': [value: DateRange]
|
||||
}>()
|
||||
|
||||
function handlePageChange(page: number) {
|
||||
emit('pageChange', page)
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Dialog v-model:open="isModalOpen" title="" size="2xl">
|
||||
<div class="space-y-4">
|
||||
<Popover>
|
||||
<PopoverTrigger as-child>
|
||||
<Button variant="outline" :class="cn('mb-1 w-[280px] justify-start text-left font-normal',
|
||||
!props.dateValue && 'text-muted-foreground')">
|
||||
<CalendarIcon class="mr-2 h-4 w-4" />
|
||||
<template v-if="props.dateValue.start">
|
||||
<template v-if="props.dateValue.end">
|
||||
{{ df.format(props.dateValue.start.toDate(getLocalTimeZone())) }} -
|
||||
{{ df.format(props.dateValue.end.toDate(getLocalTimeZone())) }}
|
||||
</template>
|
||||
|
||||
<template v-else>
|
||||
{{ df.format(props.dateValue.start.toDate(getLocalTimeZone())) }}
|
||||
</template>
|
||||
</template>
|
||||
<template v-else> Pick a date </template>
|
||||
</Button>
|
||||
</PopoverTrigger>
|
||||
<PopoverContent class="w-auto p-0">
|
||||
<RangeCalendar v-model="props.dateValue" initial-focus :number-of-months="2"
|
||||
@update:model-value="(date) => emit('update:dateValue', date)" />
|
||||
</PopoverContent>
|
||||
</Popover>
|
||||
|
||||
<PubMyUiDataTable
|
||||
v-bind="config"
|
||||
:rows="data"
|
||||
:skeleton-size="props.paginationMeta?.pageSize"
|
||||
/>
|
||||
<PaginationView :pagination-meta="props.paginationMeta" @page-change="handlePageChange" />
|
||||
</div>
|
||||
</Dialog>
|
||||
</template>
|
||||
@@ -0,0 +1,39 @@
|
||||
import type { Config } from '~/components/pub/my-ui/data-table'
|
||||
import type { Patient } from '~/models/patient'
|
||||
|
||||
export const config: Config = {
|
||||
cols: [{}, {}, {}, {}, {},],
|
||||
|
||||
headers: [
|
||||
[
|
||||
{ label: 'Tanggal Order' },
|
||||
{ label: 'No Lab' },
|
||||
{ label: 'Nama Pemeriksaan' },
|
||||
{ label: 'Tanggal Pemeriksaan' },
|
||||
],
|
||||
],
|
||||
|
||||
keys: ['birth_date', 'person.name', 'person.name', 'birth_date',],
|
||||
|
||||
parses: {
|
||||
birth_date: (rec: unknown): unknown => {
|
||||
const { person } = rec as Patient
|
||||
|
||||
if (typeof person.birthDate == 'object' && person.birthDate) {
|
||||
return (person.birthDate as Date).toLocaleDateString('id-ID')
|
||||
} else if (typeof person.birthDate == 'string') {
|
||||
return (person.birthDate as string).substring(0, 10)
|
||||
}
|
||||
return person.birthDate
|
||||
},
|
||||
},
|
||||
|
||||
components: {
|
||||
},
|
||||
|
||||
htmls: {
|
||||
// patient_address(_rec) {
|
||||
// return '-'
|
||||
// },
|
||||
},
|
||||
}
|
||||
@@ -4,22 +4,23 @@ 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'))
|
||||
const action = defineAsyncComponent(() => import('~/components/pub/my-ui/data/dropdown-action-dvvp.vue'))
|
||||
const statusBadge = defineAsyncComponent(() => import('./_common/verify-badge.vue'))
|
||||
|
||||
export const config: Config = {
|
||||
cols: [{}, {}, {}, {}, {width: 3},],
|
||||
cols: [{width: 140}, {}, {}, {width: 140}, {width: 10},],
|
||||
|
||||
headers: [
|
||||
[
|
||||
{ label: 'Tgl Rencana Kontrol' },
|
||||
{ label: 'Spesialis/Sub Spesialis' },
|
||||
{ label: 'Tgl Simpan' },
|
||||
{ label: 'DPJP' },
|
||||
{ label: 'Status SEP' },
|
||||
{ label: 'KSM' },
|
||||
{ label: 'Status' },
|
||||
{ label: 'Action' },
|
||||
],
|
||||
],
|
||||
|
||||
keys: ['birth_date', 'number', 'person.name', 'birth_date', 'action'],
|
||||
keys: ['birth_date', 'number', 'person.name', 'status', 'action'],
|
||||
|
||||
delKeyNames: [
|
||||
{ key: 'code', label: 'Kode' },
|
||||
@@ -83,6 +84,13 @@ export const config: Config = {
|
||||
component: action,
|
||||
}
|
||||
},
|
||||
status(rec, idx) {
|
||||
return {
|
||||
idx,
|
||||
rec: rec as object,
|
||||
component: statusBadge,
|
||||
}
|
||||
},
|
||||
},
|
||||
|
||||
htmls: {
|
||||
|
||||
@@ -2,42 +2,30 @@
|
||||
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'
|
||||
import DetailRow from '~/components/pub/my-ui/form/view/detail-row.vue';
|
||||
|
||||
interface Props {
|
||||
data: any
|
||||
data: any[]
|
||||
paginationMeta: PaginationMeta
|
||||
}
|
||||
|
||||
defineProps<Props>()
|
||||
|
||||
const emit = defineEmits<{
|
||||
pageChange: [page: number]
|
||||
}>()
|
||||
|
||||
function handlePageChange(page: number) {
|
||||
emit('pageChange', page)
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<article class="space-y-4">
|
||||
<h1 class="font-medium text-[0.89rem]">Pemeriksaan Pasien</h1>
|
||||
<div class="space-y-1">
|
||||
<DetailRow label="Tanggal Masuk">{{ new Date().toLocaleDateString('id-ID') }}</DetailRow>
|
||||
<DetailRow label="Tanggal Keluar">{{ new Date().toLocaleDateString('id-ID') }}</DetailRow>
|
||||
<DetailRow label="Anamnesis">{{ `-` }}</DetailRow>
|
||||
<DetailRow label="Pemeriksaan Fisik">{{ `-` }}</DetailRow>
|
||||
<DetailRow label="Pemeriksaan Penunjang">{{ `-` }}</DetailRow>
|
||||
</div>
|
||||
<Separator class="" />
|
||||
<h1 class="font-medium text-[0.89rem]">Diagnosis</h1>
|
||||
<div class="space-y-1">
|
||||
<DetailRow label="Diagnosis Utama">{{ `-` }}</DetailRow>
|
||||
<DetailRow label="Diagnosis Sekunder">{{ `-` }}</DetailRow>
|
||||
</div>
|
||||
<Separator class="" />
|
||||
<h1 class="font-medium text-[0.89rem]">Tindakan Operatif/Non Operatif</h1>
|
||||
<div class="space-y-1">
|
||||
<DetailRow label="Tindakan Operatif Utama">{{ `-` }}</DetailRow>
|
||||
<DetailRow label="Tindakan /Prosedur">{{ `-` }}</DetailRow>
|
||||
<DetailRow label="Medikamentosa">{{ `-` }}</DetailRow>
|
||||
</div>
|
||||
<Separator class="" />
|
||||
<h1 class="font-medium text-[0.89rem]">Penatalaksanaan</h1>
|
||||
<div class="space-y-1">
|
||||
<DetailRow label="Lanjutan Penatalaksanaan">{{ `-` }}</DetailRow>
|
||||
</div>
|
||||
</article>
|
||||
</template>
|
||||
<div class="space-y-4">
|
||||
<PubMyUiDataTable
|
||||
v-bind="config"
|
||||
:rows="data"
|
||||
:skeleton-size="paginationMeta?.pageSize"
|
||||
/>
|
||||
<PaginationView :pagination-meta="paginationMeta" @page-change="handlePageChange" />
|
||||
</div>
|
||||
</template>
|
||||
@@ -0,0 +1,97 @@
|
||||
<script setup lang="ts">
|
||||
import type { FormErrors } from '~/types/error'
|
||||
import { toTypedSchema } from '@vee-validate/zod'
|
||||
import FieldGroup from '~/components/pub/my-ui/form/field-group.vue'
|
||||
import Field from '~/components/pub/my-ui/form/field.vue'
|
||||
import Label from '~/components/pub/my-ui/form/label.vue'
|
||||
import Select from '~/components/pub/my-ui/form/select.vue'
|
||||
import { Form } from '~/components/pub/ui/form'
|
||||
import InputBase from '~/components/pub/my-ui/form/input-base.vue'
|
||||
import type { InstallationFormData } from '~/schemas/installation.schema'
|
||||
|
||||
|
||||
const props = defineProps<{
|
||||
schema: any
|
||||
errors?: FormErrors
|
||||
}>()
|
||||
|
||||
const emit = defineEmits<{
|
||||
submit: [values: InstallationFormData, resetForm: () => void]
|
||||
cancel: [resetForm: () => void]
|
||||
}>()
|
||||
|
||||
const formSchema = toTypedSchema(props.schema)
|
||||
|
||||
// Form submission handler
|
||||
function onSubmitForm(values: any, { resetForm }: { resetForm: () => void }) {
|
||||
const formData: InstallationFormData = {
|
||||
name: values.name || '',
|
||||
code: values.code || '',
|
||||
}
|
||||
emit('submit', formData, resetForm)
|
||||
}
|
||||
|
||||
// Form cancel handler
|
||||
function onCancelForm({ resetForm }: { resetForm: () => void }) {
|
||||
emit('cancel', resetForm)
|
||||
}
|
||||
|
||||
const items = ref([
|
||||
{ label: 'Rujukan Internal', value: 'ri' },
|
||||
{ label: 'SEP Rujukan', value: 'sr' },
|
||||
])
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Form
|
||||
v-slot="{ handleSubmit, resetForm }"
|
||||
as=""
|
||||
keep-values
|
||||
:validation-schema="formSchema"
|
||||
>
|
||||
<form id="entry-form" @submit="handleSubmit($event, (values) => onSubmitForm(values, { resetForm }))">
|
||||
<div class="mb-5 border-b border-b-slate-300 pb-3 text-lg xl:text-xl">
|
||||
<div class="flex flex-col justify-between">
|
||||
|
||||
<InputBase
|
||||
field-name="name"
|
||||
label="Nama"
|
||||
placeholder="Masukkan Nama"
|
||||
:errors="errors"/>
|
||||
<InputBase
|
||||
field-name="email"
|
||||
label="Email"
|
||||
placeholder="Masukkan Email"
|
||||
:errors="errors"/>
|
||||
|
||||
<div class="mt-2">
|
||||
<Label class="" for="password">Password</Label>
|
||||
<Field class="" id="password" :errors="errors">
|
||||
<FormField v-slot="{ componentField }" name="password">
|
||||
<FormItem>
|
||||
<FormControl>
|
||||
<Input
|
||||
id="password"
|
||||
v-bind="componentField"
|
||||
type="password"
|
||||
class="w-full"
|
||||
/>
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
</FormField>
|
||||
</Field>
|
||||
</div>
|
||||
|
||||
<InputBase
|
||||
class="mb-2"
|
||||
field-name="captha"
|
||||
label="Captha"
|
||||
placeholder="Masukkan Captha"
|
||||
:errors="errors"/>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</Form>
|
||||
</template>
|
||||
@@ -3,6 +3,14 @@ import type { ExposedForm } from '~/types/form';
|
||||
import Action from '~/components/pub/my-ui/nav-footer/ba-dr-su.vue'
|
||||
import { ResumeSchema } from '~/schemas/resume.schema';
|
||||
import Confirmation from '~/components/pub/my-ui/confirmation/confirmation.vue'
|
||||
import { CalendarDate, DateFormatter, getLocalTimeZone } from '@internationalized/date';
|
||||
import type { DateRange } from 'radix-vue';
|
||||
import { getPatients } from '~/services/patient.service';
|
||||
import ActionHistoryDialog from '~/components/app/resume/history-list/action-history-dialog.vue';
|
||||
import ConsultationHistoryDialog from '~/components/app/resume/history-list/consultation-history-dialog.vue';
|
||||
import SupportingHistoryDialog from '~/components/app/resume/history-list/supporting-history-dialog.vue';
|
||||
import FarmacyHistoryDialog from '~/components/app/resume/history-list/farmacy-history-dialog.vue';
|
||||
import NationalProgramHistoryDialog from '~/components/app/resume/history-list/national-program-history-dialog.vue';
|
||||
|
||||
// #region Props & Emits
|
||||
const props = defineProps<{
|
||||
@@ -11,14 +19,60 @@ const props = defineProps<{
|
||||
|
||||
// form related state
|
||||
const personPatientForm = ref<ExposedForm<any> | null>(null)
|
||||
const actionHistoryData = usePaginatedList({
|
||||
fetchFn: (params) => getPatients({ ...params, includes: ['person', 'person-Addresses'] }),
|
||||
entityName: 'patient',
|
||||
})
|
||||
const consultationHistoryData = usePaginatedList({
|
||||
fetchFn: (params) => getPatients({ ...params, includes: ['person', 'person-Addresses'] }),
|
||||
entityName: 'patient',
|
||||
})
|
||||
const supportingHistoryData = usePaginatedList({
|
||||
fetchFn: (params) => getPatients({ ...params, includes: ['person', 'person-Addresses'] }),
|
||||
entityName: 'patient',
|
||||
})
|
||||
const farmacyHistoryData = usePaginatedList({
|
||||
fetchFn: (params) => getPatients({ ...params, includes: ['person', 'person-Addresses'] }),
|
||||
entityName: 'patient',
|
||||
})
|
||||
const nationalProgramServiceHistoryData = usePaginatedList({
|
||||
fetchFn: (params) => getPatients({ ...params, includes: ['person', 'person-Addresses'] }),
|
||||
entityName: 'patient',
|
||||
})
|
||||
// #endregion
|
||||
|
||||
// #region State & Computed
|
||||
const router = useRouter()
|
||||
const isConfirmationOpen = ref(false)
|
||||
const isActionHistoryOpen = ref<boolean>(false)
|
||||
const isConsultationHistoryOpen = ref<boolean>(false)
|
||||
const isSupportingHistoryOpen = ref<boolean>(false)
|
||||
const isFarmacyHistoryOpen = ref<boolean>(false)
|
||||
const isNationalProgramServiceHistoryOpen = ref<boolean>(false)
|
||||
|
||||
provide(`isActionHistoryOpen`, isActionHistoryOpen)
|
||||
provide(`isConsultationHistoryOpen`, isConsultationHistoryOpen)
|
||||
provide(`isSupportingHistoryOpen`, isSupportingHistoryOpen)
|
||||
provide(`isFarmacyHistoryOpen`, isFarmacyHistoryOpen)
|
||||
provide(`isNationalProgramServiceHistoryOpen`, isNationalProgramServiceHistoryOpen)
|
||||
|
||||
const defaultDate = {
|
||||
start: new CalendarDate(2022, 1, 20),
|
||||
end: new CalendarDate(2022, 1, 20).add({ days: 20 }),
|
||||
}
|
||||
|
||||
const actionHistoryDateValue = ref(defaultDate) as Ref<DateRange>
|
||||
const consultationHistoryDateValue = ref(defaultDate) as Ref<DateRange>
|
||||
const supportingHistoryDateValue = ref(defaultDate) as Ref<DateRange>
|
||||
const farmacyHistoryDateValue = ref(defaultDate) as Ref<DateRange>
|
||||
const nationalProgramServiceSearch = ref<string>('')
|
||||
const nationalProgramServiceSelectedStatus = ref<string>('all')
|
||||
// #endregion
|
||||
|
||||
// #region Lifecycle Hooks
|
||||
onMounted(() => {
|
||||
|
||||
})
|
||||
// #endregion
|
||||
|
||||
// #region Functions
|
||||
@@ -86,7 +140,7 @@ async function handleActionClick(eventType: string) {
|
||||
<AppResumeAdd
|
||||
ref="personPatientForm"
|
||||
:schema="ResumeSchema"
|
||||
:resume-arrangement-type="personPatientForm?.values.arrangement" />
|
||||
:resume-arrangement-type="personPatientForm?.values.arrangement"/>
|
||||
|
||||
<div class="my-2 flex justify-end py-2">
|
||||
<Action :enable-draft="false"
|
||||
@@ -101,4 +155,46 @@ async function handleActionClick(eventType: string) {
|
||||
@confirm="handleConfirmAdd"
|
||||
@cancel="handleCancelAdd"
|
||||
/>
|
||||
|
||||
<ActionHistoryDialog
|
||||
v-model:is-modal-open="isActionHistoryOpen"
|
||||
v-model:date-value="actionHistoryDateValue"
|
||||
:data="actionHistoryData.data.value"
|
||||
:pagination-meta="actionHistoryData.paginationMeta"
|
||||
@page-change="actionHistoryData.handlePageChange"
|
||||
/>
|
||||
|
||||
<p v-if="isConsultationHistoryOpen === true">aaaaaaaaaaaaaaa</p>
|
||||
<ConsultationHistoryDialog
|
||||
v-model:is-modal-open="isConsultationHistoryOpen"
|
||||
v-model:date-value="consultationHistoryDateValue"
|
||||
:data="consultationHistoryData.data.value"
|
||||
:pagination-meta="consultationHistoryData.paginationMeta"
|
||||
@page-change="consultationHistoryData.handlePageChange"
|
||||
/>
|
||||
|
||||
<SupportingHistoryDialog
|
||||
v-model:is-modal-open="isSupportingHistoryOpen"
|
||||
v-model:date-value="supportingHistoryDateValue"
|
||||
:data="supportingHistoryData.data.value"
|
||||
:pagination-meta="supportingHistoryData.paginationMeta"
|
||||
@page-change="supportingHistoryData.handlePageChange"
|
||||
/>
|
||||
|
||||
<FarmacyHistoryDialog
|
||||
v-model:is-modal-open="isFarmacyHistoryOpen"
|
||||
v-model:date-value="farmacyHistoryDateValue"
|
||||
:data="farmacyHistoryData.data.value"
|
||||
:pagination-meta="farmacyHistoryData.paginationMeta"
|
||||
@page-change="farmacyHistoryData.handlePageChange"
|
||||
/>
|
||||
|
||||
<NationalProgramHistoryDialog
|
||||
v-model:is-modal-open="isNationalProgramServiceHistoryOpen"
|
||||
v-model:search-value="nationalProgramServiceSearch"
|
||||
v-model:status-value="nationalProgramServiceSelectedStatus"
|
||||
:data="nationalProgramServiceHistoryData.data.value"
|
||||
:pagination-meta="nationalProgramServiceHistoryData.paginationMeta"
|
||||
@page-change="nationalProgramServiceHistoryData.handlePageChange"
|
||||
/>
|
||||
</template>
|
||||
|
||||
@@ -10,9 +10,12 @@ import { ActionEvents } from '~/components/pub/my-ui/data/types'
|
||||
import Header from '~/components/pub/my-ui/nav-header/prep.vue'
|
||||
import SummaryCard from '~/components/pub/my-ui/summary-card/summary-card.vue'
|
||||
import { usePaginatedList } from '~/composables/usePaginatedList'
|
||||
import Action from '~/components/pub/my-ui/nav-footer/ba-dr-su.vue'
|
||||
|
||||
import { getPatients, removePatient } from '~/services/patient.service'
|
||||
import DetailRow from '~/components/pub/my-ui/form/view/detail-row.vue'
|
||||
import Dialog from '~/components/pub/my-ui/modal/dialog.vue'
|
||||
import Confirmation from '~/components/pub/my-ui/confirmation/confirmation.vue'
|
||||
|
||||
// #endregion
|
||||
|
||||
@@ -35,6 +38,7 @@ const refSearchNav: RefSearchNav = {
|
||||
}
|
||||
|
||||
const formType = ref<`a` | `b`>(`a`)
|
||||
const isVerifyDialogOpen = ref(false)
|
||||
const isRecordConfirmationOpen = ref(false)
|
||||
const summaryLoading = ref(false)
|
||||
|
||||
@@ -69,23 +73,61 @@ async function getPatientSummary() {
|
||||
summaryLoading.value = false
|
||||
}
|
||||
}
|
||||
function handleFormScreening(key: string) {
|
||||
switch (key) {
|
||||
case 'form-a':
|
||||
navigateTo("/screening-mpp/add/a")
|
||||
break;
|
||||
case 'preview-form-a':
|
||||
navigateTo('https://google.com', { external: true, open: { target: '_blank' } });
|
||||
break;
|
||||
case 'form-b':
|
||||
navigateTo("/screening-mpp/add/b")
|
||||
break;
|
||||
case 'preview-form-b':
|
||||
navigateTo('https://google.com', { external: true, open: { target: '_blank' } });
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
|
||||
async function handleActionClick(eventType: string) {
|
||||
if (eventType === 'submit') {
|
||||
// const patient: Patient = await composeFormData()
|
||||
// let createdPatientId = 0
|
||||
|
||||
// const response = await handleActionSave(
|
||||
// patient,
|
||||
// () => {},
|
||||
// () => {},
|
||||
// toast,
|
||||
// )
|
||||
|
||||
// const data = (response?.body?.data ?? null) as PatientBase | null
|
||||
// if (!data) return
|
||||
// createdPatientId = data.id
|
||||
|
||||
// If has callback provided redirect to callback with patientData
|
||||
// if (props.callbackUrl) {
|
||||
// await navigateTo(props.callbackUrl + '?patient-id=' + patient.id)
|
||||
// return
|
||||
// }
|
||||
|
||||
// Navigate to patient list or show success message
|
||||
// await navigateTo('/outpatient/encounter')
|
||||
// return
|
||||
}
|
||||
|
||||
if (eventType === 'back') {
|
||||
isVerifyDialogOpen.value = false
|
||||
}
|
||||
}
|
||||
|
||||
async function handleConfirmDelete() {
|
||||
try {
|
||||
const result = await removePatient(recId.value)
|
||||
if (result.success) {
|
||||
console.log('Patient deleted successfully')
|
||||
// Refresh the list
|
||||
await fetchData()
|
||||
} else {
|
||||
console.error('Failed to delete patient:', result)
|
||||
// Handle error - show error message to user
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error deleting patient:', error)
|
||||
// Handle error - show error message to user
|
||||
}
|
||||
}
|
||||
|
||||
function handleCancelConfirmation() {
|
||||
// Reset record state when cancelled
|
||||
recId.value = 0
|
||||
recAction.value = ''
|
||||
recItem.value = null
|
||||
}
|
||||
// #endregion
|
||||
|
||||
@@ -99,26 +141,15 @@ provide('table_data_loader', isLoading)
|
||||
// #region Watchers
|
||||
watch([recId, recAction], () => {
|
||||
switch (recAction.value) {
|
||||
case ActionEvents.showDetail:
|
||||
navigateTo({
|
||||
name: 'outpatient-encounter-id',
|
||||
params: { id: recId.value },
|
||||
})
|
||||
case ActionEvents.showVerify:
|
||||
isVerifyDialogOpen.value = true
|
||||
break
|
||||
|
||||
case ActionEvents.showEdit:
|
||||
// TODO: Handle edit action
|
||||
// isFormEntryDialogOpen.value = true
|
||||
navigateTo({
|
||||
name: 'outpatient-encounter-id-edit',
|
||||
params: { id: recId.value },
|
||||
})
|
||||
break
|
||||
|
||||
case ActionEvents.showConfirmDelete:
|
||||
// Trigger confirmation modal open
|
||||
case ActionEvents.showValidate:
|
||||
isRecordConfirmationOpen.value = true
|
||||
break
|
||||
case ActionEvents.showPrint:
|
||||
navigateTo('https://google.com', {external: true,open: { target: "_blank" },});
|
||||
break
|
||||
}
|
||||
})
|
||||
// #endregion
|
||||
@@ -126,26 +157,29 @@ watch([recId, recAction], () => {
|
||||
|
||||
<template>
|
||||
<Header :prep="{ ...headerPrep }" />
|
||||
<AppResumeList />
|
||||
|
||||
<!-- Disable dulu, ayahab kalo diminta beneran -->
|
||||
<!-- <div class="my-4 flex flex-1 flex-col gap-4 md:gap-8">
|
||||
<div class="grid gap-4 md:grid-cols-2 md:gap-8 lg:grid-cols-4">
|
||||
<template v-if="summaryLoading">
|
||||
<SummaryCard
|
||||
v-for="n in 4"
|
||||
:key="n"
|
||||
is-skeleton
|
||||
/>
|
||||
</template>
|
||||
<template v-else>
|
||||
<SummaryCard
|
||||
v-for="card in summaryData"
|
||||
:key="card.title"
|
||||
:stat="card"
|
||||
/>
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
-->
|
||||
<!-- <AppTherapyProtocolList
|
||||
:data="data"
|
||||
:pagination-meta="paginationMeta"
|
||||
@page-change="handlePageChange"/> -->
|
||||
<AppResumeList
|
||||
:data="data"
|
||||
:pagination-meta="paginationMeta"
|
||||
@page-change="handlePageChange"/>
|
||||
|
||||
<Dialog v-model:open="isVerifyDialogOpen" title="Verifikasi">
|
||||
<AppResumeVerifyDialog />
|
||||
<div class="flex justify-end">
|
||||
<Action :enable-draft="false" @click="handleActionClick" />
|
||||
</div>
|
||||
</Dialog>
|
||||
|
||||
<Confirmation
|
||||
v-model:open="isRecordConfirmationOpen"
|
||||
title="Validasi Data"
|
||||
message="Apakah Anda yakin ingin menvalidasi data ini?"
|
||||
confirm-text="Validasi"
|
||||
@confirm="handleConfirmDelete"
|
||||
@cancel="handleCancelConfirmation"
|
||||
/>
|
||||
</template>
|
||||
@@ -0,0 +1,103 @@
|
||||
<script setup lang="ts">
|
||||
import type { LinkItem, ListItemDto } from './types'
|
||||
import { ActionEvents } from './types'
|
||||
|
||||
const props = defineProps<{
|
||||
rec: ListItemDto
|
||||
}>()
|
||||
|
||||
const recId = inject<Ref<number>>('rec_id')!
|
||||
const recAction = inject<Ref<string>>('rec_action')!
|
||||
const recItem = inject<Ref<any>>('rec_item')!
|
||||
const activeKey = ref<string | null>(null)
|
||||
const linkItems: LinkItem[] = [
|
||||
{
|
||||
label: 'Detail',
|
||||
onClick: () => {
|
||||
detail()
|
||||
},
|
||||
icon: 'i-lucide-eye',
|
||||
},
|
||||
{
|
||||
label: 'Verifikasi',
|
||||
onClick: () => {
|
||||
verify()
|
||||
},
|
||||
icon: 'i-lucide-check',
|
||||
},
|
||||
{
|
||||
label: 'Validasi',
|
||||
onClick: () => {
|
||||
validate()
|
||||
},
|
||||
icon: 'i-lucide-check-check',
|
||||
},
|
||||
{
|
||||
label: 'Print',
|
||||
onClick: () => {
|
||||
print()
|
||||
},
|
||||
icon: 'i-lucide-printer',
|
||||
},
|
||||
]
|
||||
|
||||
function detail() {
|
||||
recId.value = props.rec.id || 0
|
||||
recAction.value = ActionEvents.showDetail
|
||||
recItem.value = props.rec
|
||||
}
|
||||
|
||||
function verify() {
|
||||
recId.value = props.rec.id || 0
|
||||
recAction.value = ActionEvents.showVerify
|
||||
recItem.value = props.rec
|
||||
}
|
||||
|
||||
function validate() {
|
||||
recId.value = props.rec.id || 0
|
||||
recAction.value = ActionEvents.showValidate
|
||||
recItem.value = props.rec
|
||||
}
|
||||
|
||||
function print() {
|
||||
recId.value = props.rec.id || 0
|
||||
recAction.value = ActionEvents.showPrint
|
||||
recItem.value = props.rec
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger as-child>
|
||||
<SidebarMenuButton
|
||||
size="lg"
|
||||
class="data-[state=open]:text-sidebar-accent-foreground data-[state=open]:bg-white dark:data-[state=open]:bg-slate-800"
|
||||
>
|
||||
<Icon
|
||||
name="i-lucide-chevrons-up-down"
|
||||
class="ml-auto size-4"
|
||||
/>
|
||||
</SidebarMenuButton>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent
|
||||
class="w-[--radix-dropdown-menu-trigger-width] min-w-40 rounded-lg border border-slate-200 bg-white text-black dark:border-slate-700 dark:bg-slate-800 dark:text-white"
|
||||
align="end"
|
||||
>
|
||||
<DropdownMenuGroup>
|
||||
<DropdownMenuItem
|
||||
v-for="item in linkItems"
|
||||
:key="item.label"
|
||||
class="hover:bg-gray-100 dark:hover:bg-slate-700"
|
||||
@click="item.onClick"
|
||||
@mouseenter="activeKey = item.label"
|
||||
@mouseleave="activeKey = null"
|
||||
>
|
||||
<Icon :name="item.icon ?? ''" />
|
||||
<span :class="activeKey === item.label ? 'text-sidebar-accent-foreground' : ''">{{ item.label }}</span>
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenuGroup>
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
</div>
|
||||
</template>
|
||||
@@ -76,6 +76,9 @@ export const ActionEvents = {
|
||||
showEdit: 'showEdit',
|
||||
showDetail: 'showDetail',
|
||||
showProcess: 'showProcess',
|
||||
showVerify: 'showVerify',
|
||||
showValidate: 'showValidate',
|
||||
showPrint: 'showPrint',
|
||||
}
|
||||
|
||||
export interface DataTableLoader {
|
||||
|
||||
@@ -19,6 +19,8 @@ const props = defineProps<{
|
||||
maxLength?: number
|
||||
isRequired?: boolean
|
||||
isDisabled?: boolean
|
||||
rightLabel?: string
|
||||
bottomLabel?: string
|
||||
}>()
|
||||
|
||||
function handleInput(event: Event) {
|
||||
@@ -61,14 +63,14 @@ function handleInput(event: Event) {
|
||||
v-slot="{ componentField }"
|
||||
:name="fieldName"
|
||||
>
|
||||
<FormItem>
|
||||
<FormItem :class="cn(`relative`,)">
|
||||
<FormControl>
|
||||
<Input
|
||||
:disabled="isDisabled"
|
||||
v-bind="componentField"
|
||||
:placeholder="placeholder"
|
||||
:maxlength="maxLength"
|
||||
:class="cn('focus:border-primary focus:ring-2 focus:ring-primary focus:ring-offset-0')"
|
||||
:class="cn('focus:border-primary focus:ring-2 focus:ring-primary focus:ring-offset-0', props.class)"
|
||||
autocomplete="off"
|
||||
aria-autocomplete="none"
|
||||
autocorrect="off"
|
||||
@@ -76,10 +78,12 @@ function handleInput(event: Event) {
|
||||
spellcheck="false"
|
||||
@input="handleInput"
|
||||
/>
|
||||
<p v-show="rightLabel" class="text-gray-400 absolute top-0 right-3">{{ rightLabel }}</p>
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
</FormField>
|
||||
</DE.Field>
|
||||
<p v-show="bottomLabel" class="text-gray-400 mt-1">{{ bottomLabel }}</p>
|
||||
</DE.Cell>
|
||||
</template>
|
||||
|
||||
@@ -47,7 +47,7 @@ function handleInput(event: Event) {
|
||||
<template>
|
||||
<DE.Cell :col-span="colSpan || 1">
|
||||
<DE.Label
|
||||
class="mb-1 font-medium"
|
||||
class="mb-1"
|
||||
v-if="label !== ''"
|
||||
:label-for="fieldName"
|
||||
:is-required="isRequired && !isDisabled"
|
||||
|
||||
@@ -3,6 +3,31 @@ import type { CreateDto } from '~/models/consultation'
|
||||
|
||||
export type ResumeArrangementType = "krs" | "mrs" | "pindahIgd" | "rujuk" | "rujukBalik" | "meninggal" | "other"
|
||||
|
||||
const SecondaryDiagnosisSchema = z.object({
|
||||
diagnosis: z.string({ required_error: 'Diagnosis harus diisi' }),
|
||||
icd10: z.string({ required_error: 'ICD 10 harus diisi' }),
|
||||
diagnosisBasis: z.string({ required_error: 'Dasar Diagnosis harus diisi' })
|
||||
.min(1, 'Uraian minimum 1 karakter')
|
||||
.max(2048, 'Uraian maksimum 2048 karakter'),
|
||||
})
|
||||
|
||||
const SecondaryActionSchema = z.object({
|
||||
action: z.string({ required_error: 'Action harus diisi' }),
|
||||
icd9: z.string({ required_error: 'ICD 10 harus diisi' }),
|
||||
actionBasis: z.string({ required_error: 'Dasar Action harus diisi' })
|
||||
.min(1, 'Uraian minimum 1 karakter')
|
||||
.max(2048, 'Uraian maksimum 2048 karakter'),
|
||||
})
|
||||
|
||||
const ConsultationSchema = z.object({
|
||||
consultation: z.string({ required_error: 'Consultation harus diisi' })
|
||||
.min(1, 'Uraian minimum 1 karakter')
|
||||
.max(2048, 'Uraian maksimum 2048 karakter'),
|
||||
consultationReply: z.string({ required_error: 'Jawaban Consultation harus diisi' })
|
||||
.min(1, 'Uraian minimum 1 karakter')
|
||||
.max(2048, 'Uraian maksimum 2048 karakter'),
|
||||
})
|
||||
|
||||
const ResumeSchema = z.object({
|
||||
inDate: z.string({ required_error: 'Tanggal harus diisi' }),
|
||||
outDate: z.string({ required_error: 'Tanggal harus diisi' }),
|
||||
@@ -17,19 +42,25 @@ const ResumeSchema = z.object({
|
||||
.max(2048, 'Uraian maksimum 2048 karakter'),
|
||||
|
||||
primaryDiagnosis: z.string({ required_error: 'Diagnosis harus diisi' }),
|
||||
secondaryDiagnosis: z.array(z.string()).optional().default([]),
|
||||
secondaryDiagnosis: z.array(SecondaryDiagnosisSchema).optional(),
|
||||
|
||||
primaryOperativeNonOperativeAct: z.string({ required_error: 'Diagnosis harus diisi' }),
|
||||
secondaryOperativeNonOperativeAct: z.array(z.string()).optional().default([]),
|
||||
secondaryOperativeNonOperativeAct: z.array(SecondaryActionSchema).optional(),
|
||||
medikamentosa: z.string({ required_error: 'Uraian harus diisi' })
|
||||
.min(1, 'Uraian minimum 1 karakter')
|
||||
.max(2048, 'Uraian maksimum 2048 karakter'),
|
||||
|
||||
consultation: z.array(ConsultationSchema).optional(),
|
||||
|
||||
arrangement: z.custom<ResumeArrangementType>().default("krs"),
|
||||
faskes: z.string({ required_error: 'Faskes harus diisi' }).optional(),
|
||||
clinic: z.string({ required_error: 'Klinik harus diisi' }).optional(),
|
||||
deathDate: z.string({ required_error: 'Tanggal harus diisi' }).optional(),
|
||||
deathCause: z.array(z.string()).optional().default([]),
|
||||
deathCauseDescription: z.string({ required_error: 'Uraian harus diisi' })
|
||||
.min(1, 'Uraian minimum 1 karakter')
|
||||
.max(2048, 'Uraian maksimum 2048 karakter')
|
||||
.optional(),
|
||||
keterangan: z.string({ required_error: 'Uraian harus diisi' })
|
||||
.min(1, 'Uraian minimum 1 karakter')
|
||||
.max(2048, 'Uraian maksimum 2048 karakter')
|
||||
|
||||
Reference in New Issue
Block a user