feat(subspecialist-position): implement crud operations for subspecialist positions

- Add new handler, service, and schema files for subspecialist position
- Update list configuration and entry form components
- Modify list view to display subspecialist position data
- Include subspecialist relation in position model
This commit is contained in:
Khafid Prayoga
2025-10-31 14:57:45 +07:00
parent d3090d04ef
commit ba0ac753b2
8 changed files with 162 additions and 55 deletions
@@ -7,18 +7,18 @@ import Label from '~/components/pub/my-ui/doc-entry/label.vue'
import Combobox from '~/components/pub/my-ui/combobox/combobox.vue'
// Types
import type { DivisionPositionFormData } from '~/schemas/division-position.schema'
import type { SubSpecialistPositionFormData } from '~/schemas/subspecialist-position.schema'
// Helpers
import type z from 'zod'
import { toTypedSchema } from '@vee-validate/zod'
import { useForm } from 'vee-validate'
import { genBase } from '~/models/_base'
import { genDivisionPosition } from '~/models/division-position'
import { genSubSpecialistPosition } from '~/models/subspecialist-position'
interface Props {
schema: z.ZodSchema<any>
divisionId: number
subSpecialists: any[]
employees: any[]
values: any
isLoading?: boolean
@@ -26,21 +26,21 @@ interface Props {
}
const props = defineProps<Props>()
const isLoading = props.isLoading !== undefined ? props.isLoading : false
const isReadonly = props.isReadonly !== undefined ? props.isReadonly : false
const emit = defineEmits<{
submit: [values: DivisionPositionFormData, resetForm: () => void]
submit: [values: SubSpecialistPositionFormData, resetForm: () => void]
cancel: [resetForm: () => void]
}>()
const { defineField, errors, meta } = useForm({
validationSchema: toTypedSchema(props.schema),
initialValues: genDivisionPosition() as Partial<DivisionPositionFormData>,
initialValues: genSubSpecialistPosition() as Partial<SubSpecialistPositionFormData>,
})
const [code, codeAttrs] = defineField('code')
const [name, nameAttrs] = defineField('name')
const [subSpecialist, subSpecialistAttrs] = defineField('subspecialist_id')
const [employee, employeeAttrs] = defineField('employee_id')
const [headStatus, headStatusAttrs] = defineField('headStatus')
@@ -62,6 +62,8 @@ const headStatusStr = computed<string>({
if (props.values) {
if (props.values.code !== undefined) code.value = props.values.code
if (props.values.name !== undefined) name.value = props.values.name
if (props.values.subspecialist_id !== undefined)
subSpecialist.value = props.values.subspecialist_id ? Number(props.values.subspecialist_id) : null
if (props.values.employee_id !== undefined)
employee.value = props.values.employee_id ? Number(props.values.employee_id) : null
if (props.values.headStatus !== undefined) headStatus.value = !!props.values.headStatus
@@ -70,20 +72,18 @@ if (props.values) {
const resetForm = () => {
code.value = ''
name.value = ''
subSpecialist.value = null
employee.value = null
headStatus.value = false
}
// Form submission handler
function onSubmitForm() {
const formData: DivisionPositionFormData = {
const formData: SubSpecialistPositionFormData = {
...genBase(),
name: name.value || '',
code: code.value || '',
// readonly based on detail division
division_id: props.divisionId,
subspecialist_id: subSpecialist.value || null,
employee_id: employee.value || null,
headStatus: headStatus.value !== undefined ? headStatus.value : undefined,
}
@@ -98,7 +98,7 @@ function onCancelForm() {
<template>
<form
id="form-division-position"
id="form-specialist-position"
@submit.prevent
>
<Block
@@ -107,7 +107,7 @@ function onCancelForm() {
:colCount="1"
>
<Cell>
<Label height="compact">Kode Jabatan</Label>
<Label height="compact">Kode</Label>
<Field :errMessage="errors.code">
<Input
id="code"
@@ -118,7 +118,7 @@ function onCancelForm() {
</Field>
</Cell>
<Cell>
<Label height="compact">Nama Jabatan</Label>
<Label height="compact">Nama Posisi</Label>
<Field :errMessage="errors.name">
<Input
id="name"
@@ -129,7 +129,22 @@ function onCancelForm() {
</Field>
</Cell>
<Cell>
<Label height="compact">Pengisi Jabatan</Label>
<Label height="compact">Sub Spesialis</Label>
<Field :errMessage="errors.subspecialist_id">
<Combobox
id="specialist"
v-model="subSpecialist"
v-bind="subSpecialistAttrs"
:items="subSpecialists"
:is-disabled="isLoading || isReadonly"
placeholder="Pilih Sub Spesialis"
search-placeholder="Cari Sub Spesialis"
empty-message="Item tidak ditemukan"
/>
</Field>
</Cell>
<Cell>
<Label height="compact">Karyawan</Label>
<Field :errMessage="errors.employee_id">
<Combobox
id="employee"
@@ -1,6 +1,6 @@
import type { Config, RecComponent } from '~/components/pub/my-ui/data-table'
import { defineAsyncComponent } from 'vue'
import type { DivisionPosition } from '~/models/division-position'
import type { SubSpecialistPosition } from '~/models/subspecialist-position'
type SmallDetailDto = any
@@ -13,14 +13,14 @@ export const config: Config = {
[
{ label: 'Kode Posisi' },
{ label: 'Nama Posisi' },
{ label: 'Nama Divisi ' },
{ label: 'Nama Sub Spesialis ' },
{ label: 'Karyawan' },
{ label: 'Status Kepala' },
{ label: '' },
],
],
keys: ['code', 'name', 'division', 'employee', 'head', 'action'],
keys: ['code', 'name', 'subspecialist', 'employee', 'head', 'action'],
delKeyNames: [
{ key: 'code', label: 'Kode' },
@@ -28,12 +28,12 @@ export const config: Config = {
],
parses: {
division: (rec: unknown): unknown => {
const recX = rec as SmallDetailDto
return recX.division?.name || '-'
subspecialist: (rec: unknown): unknown => {
const recX = rec as SubSpecialistPosition
return recX.subspecialist?.name || '-'
},
employee: (rec: unknown): unknown => {
const recX = rec as DivisionPosition
const recX = rec as SubSpecialistPosition
const fullName = [recX.employee?.person.frontTitle, recX.employee?.person.name, recX.employee?.person.endTitle]
.filter(Boolean)
.join(' ')
+4 -1
View File
@@ -31,6 +31,9 @@ function handlePageChange(page: number) {
:rows="data"
:skeleton-size="paginationMeta?.pageSize"
/>
<PaginationView :pagination-meta="paginationMeta" @page-change="handlePageChange" />
<PaginationView
:pagination-meta="paginationMeta"
@page-change="handlePageChange"
/>
</div>
</template>