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:
@@ -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(' ')
|
||||
|
||||
@@ -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>
|
||||
|
||||
Reference in New Issue
Block a user