c340de3114
add handler, service, schema and update components for specialist position management update list configuration and form to handle specialist relations
204 lines
5.7 KiB
Vue
204 lines
5.7 KiB
Vue
<script setup lang="ts">
|
|
// Components
|
|
import Dialog from '~/components/pub/my-ui/modal/dialog.vue'
|
|
import Header from '~/components/pub/my-ui/nav-header/prep.vue'
|
|
import RecordConfirmation from '~/components/pub/my-ui/confirmation/record-confirmation.vue'
|
|
import AppSpecialistPositionList from '~/components/app/specialist-position/list.vue'
|
|
import AppSpecialistPositionEntryForm from '~/components/app/specialist-position/entry-form.vue'
|
|
|
|
// Helpers
|
|
import { usePaginatedList } from '~/composables/usePaginatedList'
|
|
import { toast } from '~/components/pub/ui/toast'
|
|
import { config } from '~/components/app/specialist-position/list.cfg'
|
|
|
|
// Types
|
|
import { ActionEvents, type HeaderPrep } from '~/components/pub/my-ui/data/types'
|
|
import { type SpecialistPositionFormData, SpecialistPositionSchema } from '~/schemas/specialist-position.schema'
|
|
|
|
// Handlers
|
|
import {
|
|
recId,
|
|
recAction,
|
|
recItem,
|
|
isReadonly,
|
|
isProcessing,
|
|
isFormEntryDialogOpen,
|
|
isRecordConfirmationOpen,
|
|
onResetState,
|
|
handleActionSave,
|
|
handleActionEdit,
|
|
handleActionRemove,
|
|
handleCancelForm,
|
|
} from '~/handlers/specialist-position.handler'
|
|
|
|
// Services
|
|
import { getList, getDetail } from '~/services/specialist-position.service'
|
|
import { getValueLabelList as getValueLabelSpecialistList } from '~/services/specialist.service'
|
|
import { getValueLabelList as getEmployeeLabelList } from '~/services/employee.service'
|
|
|
|
const specialists = ref<{ value: string | number; label: string }[]>([])
|
|
const employees = ref<{ value: string | number; label: string }[]>([])
|
|
const title = ref('')
|
|
|
|
const {
|
|
data,
|
|
isLoading,
|
|
paginationMeta,
|
|
searchInput,
|
|
handlePageChange,
|
|
handleSearch,
|
|
fetchData: getSpecialistList,
|
|
} = usePaginatedList({
|
|
fetchFn: async (params: any) => {
|
|
const result = await getList({
|
|
search: params.search,
|
|
sort: 'createdAt:asc',
|
|
'page-number': params['page-number'] || 0,
|
|
'page-size': params['page-size'] || 10,
|
|
includes: 'specialist,Employee.Person',
|
|
})
|
|
return { success: result.success || false, body: result.body || {} }
|
|
},
|
|
entityName: 'specialist-position',
|
|
})
|
|
|
|
const headerPrep: HeaderPrep = {
|
|
title: 'Spesialis - Posisi',
|
|
icon: 'i-lucide-box',
|
|
refSearchNav: {
|
|
placeholder: 'Cari (min. 3 karakter)...',
|
|
minLength: 3,
|
|
debounceMs: 500,
|
|
showValidationFeedback: true,
|
|
onInput: (value: string) => {
|
|
searchInput.value = value
|
|
},
|
|
onClick: () => {},
|
|
onClear: () => {},
|
|
},
|
|
addNav: {
|
|
label: 'Tambah',
|
|
icon: 'i-lucide-plus',
|
|
onClick: () => {
|
|
recItem.value = null
|
|
recId.value = 0
|
|
isFormEntryDialogOpen.value = true
|
|
isReadonly.value = false
|
|
},
|
|
},
|
|
}
|
|
|
|
provide('rec_id', recId)
|
|
provide('rec_action', recAction)
|
|
provide('rec_item', recItem)
|
|
provide('table_data_loader', isLoading)
|
|
|
|
const getCurrentSpecialistDetail = async (id: number | string) => {
|
|
const result = await getDetail(id)
|
|
if (result.success) {
|
|
const currentValue = result.body?.data || {}
|
|
recItem.value = currentValue
|
|
isFormEntryDialogOpen.value = true
|
|
}
|
|
}
|
|
// Watch for row actions when recId or recAction changes
|
|
watch([recId, recAction], () => {
|
|
switch (recAction.value) {
|
|
case ActionEvents.showDetail:
|
|
getCurrentSpecialistDetail(recId.value)
|
|
title.value = 'Detail Spesialis Posisi'
|
|
isReadonly.value = true
|
|
break
|
|
case ActionEvents.showEdit:
|
|
getCurrentSpecialistDetail(recId.value)
|
|
title.value = 'Edit Spesialis Posisi'
|
|
isReadonly.value = false
|
|
break
|
|
case ActionEvents.showConfirmDelete:
|
|
isRecordConfirmationOpen.value = true
|
|
break
|
|
}
|
|
})
|
|
|
|
onMounted(async () => {
|
|
try {
|
|
specialists.value = await getValueLabelSpecialistList({ sort: 'createdAt:asc', 'page-size': 100 })
|
|
employees.value = await getEmployeeLabelList({ sort: 'createdAt:asc', 'page-size': 100, includes: 'person' })
|
|
} catch (err) {
|
|
console.log(err)
|
|
// show toast
|
|
toast({
|
|
title: 'Terjadi Kesalahan',
|
|
description: 'Terjadi kesalahan saat memuat data',
|
|
variant: 'destructive',
|
|
})
|
|
}
|
|
})
|
|
</script>
|
|
|
|
<template>
|
|
<Header
|
|
v-model="searchInput"
|
|
:prep="headerPrep"
|
|
:ref-search-nav="headerPrep.refSearchNav"
|
|
@search="handleSearch"
|
|
/>
|
|
<AppSpecialistPositionList
|
|
:data="data"
|
|
:pagination-meta="paginationMeta"
|
|
@page-change="handlePageChange"
|
|
/>
|
|
<Dialog
|
|
v-model:open="isFormEntryDialogOpen"
|
|
:title="!!recItem ? title : 'Tambah Spesialis'"
|
|
size="lg"
|
|
prevent-outside
|
|
@update:open="
|
|
(value: any) => {
|
|
onResetState()
|
|
isFormEntryDialogOpen = value
|
|
}
|
|
"
|
|
>
|
|
<AppSpecialistPositionEntryForm
|
|
:schema="SpecialistPositionSchema"
|
|
:specialists="specialists"
|
|
:employees="employees"
|
|
:values="recItem"
|
|
:is-loading="isProcessing"
|
|
:is-readonly="isReadonly"
|
|
@submit="
|
|
(values: SpecialistPositionFormData | Record<string, any>, resetForm: () => void) => {
|
|
if (recId > 0) {
|
|
handleActionEdit(recId, values, getSpecialistList, resetForm, toast)
|
|
return
|
|
}
|
|
handleActionSave(values, getSpecialistList, resetForm, toast)
|
|
}
|
|
"
|
|
@cancel="handleCancelForm"
|
|
/>
|
|
</Dialog>
|
|
<!-- Record Confirmation Modal -->
|
|
<RecordConfirmation
|
|
v-model:open="isRecordConfirmationOpen"
|
|
action="delete"
|
|
:record="recItem"
|
|
@confirm="() => handleActionRemove(recId, getSpecialistList, toast)"
|
|
@cancel=""
|
|
>
|
|
<template #default="{ record }">
|
|
<div class="space-y-1 text-sm">
|
|
<p
|
|
v-for="field in config.delKeyNames"
|
|
:key="field.key"
|
|
:v-if="record?.[field.key]"
|
|
>
|
|
<span class="font-semibold">{{ field.label }}:</span>
|
|
{{ record[field.key] }}
|
|
</p>
|
|
</div>
|
|
</template>
|
|
</RecordConfirmation>
|
|
</template>
|