feat(material): finishing integration of material

This commit is contained in:
riefive
2025-09-24 17:12:01 +07:00
parent 93a5abba36
commit c3c21f28e7
7 changed files with 67 additions and 44 deletions

No files matched your search

+7 -4
View File
@@ -15,10 +15,12 @@ interface Props {
schema: z.ZodSchema<any> schema: z.ZodSchema<any>
uoms: any[] uoms: any[]
values: any values: any
isReadonly?: boolean
} }
const isLoading = ref(false) const isLoading = ref(false)
const props = defineProps<Props>() const props = defineProps<Props>()
const isReadonly = props.isReadonly !== undefined ? props.isReadonly : false
const emit = defineEmits<{ const emit = defineEmits<{
submit: [values: MaterialFormData, resetForm: () => void] submit: [values: MaterialFormData, resetForm: () => void]
cancel: [resetForm: () => void] cancel: [resetForm: () => void]
@@ -75,13 +77,13 @@ function onCancelForm() {
<Cell> <Cell>
<Label height="">Kode</Label> <Label height="">Kode</Label>
<Field :errMessage="errors.code"> <Field :errMessage="errors.code">
<Input id="code" v-model="code" v-bind="codeAttrs" :disabled="isLoading" /> <Input id="code" v-model="code" v-bind="codeAttrs" :disabled="isLoading || isReadonly" />
</Field> </Field>
</Cell> </Cell>
<Cell> <Cell>
<Label height="compact">Nama</Label> <Label height="compact">Nama</Label>
<Field :errMessage="errors.name"> <Field :errMessage="errors.name">
<Input id="name" v-model="name" v-bind="nameAttrs" :disabled="isLoading" /> <Input id="name" v-model="name" v-bind="nameAttrs" :disabled="isLoading || isReadonly" />
</Field> </Field>
</Cell> </Cell>
<Cell> <Cell>
@@ -94,20 +96,21 @@ function onCancelForm() {
placeholder="Pilih satuan" placeholder="Pilih satuan"
v-bind="uomAttrs" v-bind="uomAttrs"
:items="uoms" :items="uoms"
:disabled="isLoading" :disabled="isLoading || isReadonly"
/> />
</Field> </Field>
</Cell> </Cell>
<Cell> <Cell>
<Label height="compact">Stok</Label> <Label height="compact">Stok</Label>
<Field :errMessage="errors.stock"> <Field :errMessage="errors.stock">
<Input id="stock" v-model="stock" type="number" v-bind="stockAttrs" :disabled="isLoading" /> <Input id="stock" v-model="stock" type="number" v-bind="stockAttrs" :disabled="isLoading || isReadonly" />
</Field> </Field>
</Cell> </Cell>
</Block> </Block>
<div class="my-2 flex justify-end gap-2 py-2"> <div class="my-2 flex justify-end gap-2 py-2">
<Button type="button" variant="secondary" class="w-[120px]" @click="onCancelForm"> Kembali </Button> <Button type="button" variant="secondary" class="w-[120px]" @click="onCancelForm"> Kembali </Button>
<Button <Button
v-if="!isReadonly"
type="button" type="button"
class="w-[120px]" class="w-[120px]"
:disabled="isLoading || !meta.valid" :disabled="isLoading || !meta.valid"
+20 -19
View File
@@ -14,16 +14,19 @@ import Label from '~/components/pub/custom-ui/doc-entry/label.vue'
interface Props { interface Props {
schema: z.ZodSchema<any> schema: z.ZodSchema<any>
uoms: any[] uoms: any[]
values: any
isReadonly?: boolean
} }
const isLoading = ref(false) const isLoading = ref(false)
const props = defineProps<Props>() const props = defineProps<Props>()
const isReadonly = props.isReadonly !== undefined ? props.isReadonly : false
const emit = defineEmits<{ const emit = defineEmits<{
submit: [values: DeviceFormData, resetForm: () => void] submit: [values: DeviceFormData, resetForm: () => void]
cancel: [resetForm: () => void] cancel: [resetForm: () => void]
}>() }>()
const { handleSubmit, defineField, errors } = useForm({ const { defineField, errors, meta } = useForm({
validationSchema: toTypedSchema(props.schema), validationSchema: toTypedSchema(props.schema),
initialValues: { initialValues: {
code: '', code: '',
@@ -37,6 +40,13 @@ const [code, codeAttrs] = defineField('code')
const [name, nameAttrs] = defineField('name') const [name, nameAttrs] = defineField('name')
const [uom, uomAttrs] = defineField('uom_code') const [uom, uomAttrs] = defineField('uom_code')
// Fill fields from props.values if provided
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.uom_code !== undefined) uom.value = props.values.uom_code
}
const resetForm = () => { const resetForm = () => {
code.value = '' code.value = ''
name.value = '' name.value = ''
@@ -46,9 +56,9 @@ const resetForm = () => {
// Form submission handler // Form submission handler
function onSubmitForm(values: any) { function onSubmitForm(values: any) {
const formData: DeviceFormData = { const formData: DeviceFormData = {
name: values.name || '', name: name.value || '',
code: values.code || '', code: code.value || '',
uom_code: values.uom_code || '', uom_code: uom.value || '',
} }
emit('submit', formData, resetForm) emit('submit', formData, resetForm)
} }
@@ -61,27 +71,17 @@ function onCancelForm() {
<template> <template>
<form id="form-tools"> <form id="form-tools">
<Block labelSize="thin" class="!mb-2.5 xl:!mb-3 !pt-0" :colCount="1"> <Block labelSize="thin" class="!mb-2.5 !pt-0 xl:!mb-3" :colCount="1">
<Cell> <Cell>
<Label height="compact">Kode</Label> <Label height="compact">Kode</Label>
<Field :errMessage="errors.code"> <Field :errMessage="errors.code">
<Input <Input id="code" v-model="code" v-bind="codeAttrs" :disabled="isLoading" />
id="code"
v-model="code"
v-bind="codeAttrs"
:disabled="isLoading"
/>
</Field> </Field>
</Cell> </Cell>
<Cell> <Cell>
<Label height="compact">Nama</Label> <Label height="compact">Nama</Label>
<Field :errMessage="errors.name"> <Field :errMessage="errors.name">
<Input <Input id="name" v-model="name" v-bind="nameAttrs" :disabled="isLoading" />
id="name"
v-model="name"
v-bind="nameAttrs"
:disabled="isLoading"
/>
</Field> </Field>
</Cell> </Cell>
<Cell> <Cell>
@@ -102,10 +102,11 @@ function onCancelForm() {
<div class="my-2 flex justify-end gap-2 py-2"> <div class="my-2 flex justify-end gap-2 py-2">
<Button variant="secondary" class="w-[120px]" @click="onCancelForm"> Kembali </Button> <Button variant="secondary" class="w-[120px]" @click="onCancelForm"> Kembali </Button>
<Button <Button
v-if="!isReadonly"
type="button" type="button"
class="w-[120px]" class="w-[120px]"
:disabled="isLoading" :disabled="isLoading || !meta.valid"
@click="handleSubmit(onSubmitForm)" @click="onSubmitForm"
> >
Simpan Simpan
</Button> </Button>
+16 -3
View File
@@ -15,6 +15,7 @@ import {
recId, recId,
recAction, recAction,
recItem, recItem,
isReadonly,
isProcessing, isProcessing,
isFormEntryDialogOpen, isFormEntryDialogOpen,
isRecordConfirmationOpen, isRecordConfirmationOpen,
@@ -29,6 +30,7 @@ import { getSourceMaterials, getSourceMaterialDetail } from '~/services/material
import { getSourceUoms } from '~/services/uom.service' import { getSourceUoms } from '~/services/uom.service'
const uoms = ref<{ value: string; label: string }[]>([]) const uoms = ref<{ value: string; label: string }[]>([])
const title = ref('')
const getEquipmentDetail = async (id: number | string) => { const getEquipmentDetail = async (id: number | string) => {
const result = await getSourceMaterialDetail(id) const result = await getSourceMaterialDetail(id)
@@ -85,7 +87,10 @@ const headerPrep: HeaderPrep = {
label: 'Tambah Perlengkapan', label: 'Tambah Perlengkapan',
icon: 'i-lucide-plus', icon: 'i-lucide-plus',
onClick: () => { onClick: () => {
recItem.value = null
recId.value = 0
isFormEntryDialogOpen.value = true isFormEntryDialogOpen.value = true
isReadonly.value = false
}, },
}, },
} }
@@ -98,8 +103,15 @@ provide('table_data_loader', isLoading)
// Watch for row actions // Watch for row actions
watch(recId, () => { watch(recId, () => {
switch (recAction.value) { switch (recAction.value) {
case ActionEvents.showDetail:
getEquipmentDetail(recId.value)
title.value = 'Detail Perlengkapan'
isReadonly.value = true
break
case ActionEvents.showEdit: case ActionEvents.showEdit:
getEquipmentDetail(recId.value) getEquipmentDetail(recId.value)
title.value = 'Edit Perlengkapan'
isReadonly.value = false
break break
case ActionEvents.showConfirmDelete: case ActionEvents.showConfirmDelete:
isRecordConfirmationOpen.value = true isRecordConfirmationOpen.value = true
@@ -122,7 +134,7 @@ onMounted(async () => {
<Dialog <Dialog
v-model:open="isFormEntryDialogOpen" v-model:open="isFormEntryDialogOpen"
:title="!!recItem ? 'Edit Perlengkapan' : 'Tambah Perlengkapan'" :title="!!recItem ? title : 'Tambah Perlengkapan'"
size="lg" size="lg"
prevent-outside prevent-outside
> >
@@ -131,11 +143,12 @@ onMounted(async () => {
:values="recItem" :values="recItem"
:uoms="uoms" :uoms="uoms"
:is-loading="isProcessing" :is-loading="isProcessing"
:is-readonly="isReadonly"
@submit=" @submit="
(values: MaterialFormData, resetForm: any) => { (values: MaterialFormData, resetForm: any) => {
if (!!recId) { if (recId > 0) {
handleActionEdit(recId, values, getEquipmentList, resetForm) handleActionEdit(recId, values, getEquipmentList, resetForm)
return return
} }
handleActionSave(values, getEquipmentList, resetForm) handleActionSave(values, getEquipmentList, resetForm)
} }
+2 -2
View File
@@ -1,7 +1,7 @@
import { ref } from 'vue' import { ref } from 'vue'
// Services // Services
import { postSourceDevice, putSourceDevice, removeSourceDevice } from '~/services/device.service' import { postSourceDevice, patchSourceDevice, removeSourceDevice } from '~/services/device.service'
const recId = ref<number>(0) const recId = ref<number>(0)
const recAction = ref<string>('') const recAction = ref<string>('')
@@ -43,7 +43,7 @@ export async function handleActionEdit(id: number | string, values: any, refresh
let isSuccess = false let isSuccess = false
isProcessing.value = true isProcessing.value = true
try { try {
const result = await putSourceDevice(id, values) const result = await patchSourceDevice(id, values)
if (result.success) { if (result.success) {
isFormEntryDialogOpen.value = false isFormEntryDialogOpen.value = false
isSuccess = true isSuccess = true
+4 -3
View File
@@ -1,11 +1,12 @@
import { ref } from 'vue' import { ref } from 'vue'
// Services // Services
import { postSourceMaterial, putSourceMaterial, removeSourceMaterial } from '~/services/material.service' import { postSourceMaterial, patchSourceMaterial, removeSourceMaterial } from '~/services/material.service'
const recId = ref<number>(0) const recId = ref<number>(0)
const recAction = ref<string>('') const recAction = ref<string>('')
const recItem = ref<any>(null) const recItem = ref<any>(null)
const isReadonly = ref(false)
const isProcessing = ref(false) const isProcessing = ref(false)
const isFormEntryDialogOpen = ref(false) const isFormEntryDialogOpen = ref(false)
const isRecordConfirmationOpen = ref(false) const isRecordConfirmationOpen = ref(false)
@@ -43,7 +44,7 @@ export async function handleActionEdit(id: number | string, values: any, refresh
let isSuccess = false let isSuccess = false
isProcessing.value = true isProcessing.value = true
try { try {
const result = await putSourceMaterial(id, values) const result = await patchSourceMaterial(id, values)
if (result.success) { if (result.success) {
isFormEntryDialogOpen.value = false isFormEntryDialogOpen.value = false
isSuccess = true isSuccess = true
@@ -84,4 +85,4 @@ export function handleCancelForm(reset: () => void) {
}, 500) }, 500)
} }
export { recId, recAction, recItem, isProcessing, isFormEntryDialogOpen, isRecordConfirmationOpen } export { recId, recAction, recItem, isReadonly, isProcessing, isFormEntryDialogOpen, isRecordConfirmationOpen }
+16 -11
View File
@@ -16,9 +16,7 @@ export async function getSourceDevices(params: any = null) {
const resp = await xfetch(url, 'GET') const resp = await xfetch(url, 'GET')
const result: any = {} const result: any = {}
result.success = resp.success result.success = resp.success
if (resp.success) { result.body = (resp.body as Record<string, any>) || {}
result.data = (resp.body as Record<string, any>).data
}
return result return result
} catch (error) { } catch (error) {
console.error('Error fetching source devices:', error) console.error('Error fetching source devices:', error)
@@ -31,9 +29,7 @@ export async function getSourceDeviceDetail(id: string | number) {
const resp = await xfetch(`/api/v1/device/${id}`, 'GET') const resp = await xfetch(`/api/v1/device/${id}`, 'GET')
const result: any = {} const result: any = {}
result.success = resp.success result.success = resp.success
if (resp.success) { result.body = (resp.body as Record<string, any>) || {}
result.data = (resp.body as Record<string, any>).data
}
return result return result
} catch (error) { } catch (error) {
console.error('Error fetching device detail:', error) console.error('Error fetching device detail:', error)
@@ -44,17 +40,23 @@ export async function getSourceDeviceDetail(id: string | number) {
export async function postSourceDevice(data: any) { export async function postSourceDevice(data: any) {
try { try {
const resp = await xfetch('/api/v1/device', 'POST', data) const resp = await xfetch('/api/v1/device', 'POST', data)
return resp const result: any = {}
result.success = resp.success
result.body = (resp.body as Record<string, any>) || {}
return result
} catch (error) { } catch (error) {
console.error('Error creating device:', error) console.error('Error creating device:', error)
throw new Error('Failed to create device') throw new Error('Failed to create device')
} }
} }
export async function putSourceDevice(id: string | number, data: any) { export async function patchSourceDevice(id: string | number, data: any) {
try { try {
const resp = await xfetch(`/api/v1/device/${id}`, 'PUT', data) const resp = await xfetch(`/api/v1/device/${id}`, 'PATCH', data)
return resp const result: any = {}
result.success = resp.success
result.body = (resp.body as Record<string, any>) || {}
return result
} catch (error) { } catch (error) {
console.error('Error updating device:', error) console.error('Error updating device:', error)
throw new Error('Failed to update device') throw new Error('Failed to update device')
@@ -64,7 +66,10 @@ export async function putSourceDevice(id: string | number, data: any) {
export async function removeSourceDevice(id: string | number) { export async function removeSourceDevice(id: string | number) {
try { try {
const resp = await xfetch(`/api/v1/device/${id}`, 'DELETE') const resp = await xfetch(`/api/v1/device/${id}`, 'DELETE')
return resp const result: any = {}
result.success = resp.success
result.body = (resp.body as Record<string, any>) || {}
return result
} catch (error) { } catch (error) {
console.error('Error deleting device:', error) console.error('Error deleting device:', error)
throw new Error('Failed to delete device') throw new Error('Failed to delete device')
+2 -2
View File
@@ -50,9 +50,9 @@ export async function postSourceMaterial(record: any) {
} }
} }
export async function putSourceMaterial(id: number | string, record: any) { export async function patchSourceMaterial(id: number | string, record: any) {
try { try {
const resp = await xfetch(`/api/v1/material/${id}`, 'PUT', record) const resp = await xfetch(`/api/v1/material/${id}`, 'PATCH', record)
const result: any = {} const result: any = {}
result.success = resp.success result.success = resp.success
result.body = (resp.body as Record<string, any>) || {} result.body = (resp.body as Record<string, any>) || {}