Files
manja_dev_ui/src/views/tickets/TicketMaterials.vue
T
sean bd77e1a4e7
NPM Installation / build (16.x, ubuntu-latest) (push) Has been cancelled
NPM Installation / build (16.x, windows-latest) (push) Has been cancelled
NPM Installation / build (17.x, ubuntu-latest) (push) Has been cancelled
NPM Installation / build (17.x, windows-latest) (push) Has been cancelled
NPM Installation / build (18.x, ubuntu-latest) (push) Has been cancelled
NPM Installation / build (18.x, windows-latest) (push) Has been cancelled
Ticket material
2026-07-03 16:26:00 +07:00

432 lines
12 KiB
Vue

<script setup>
import { ref, reactive, computed, watch, onMounted } from 'vue'
import Swal from 'sweetalert2'
import { useMaterialStore } from '@/stores/materialStore'
import { materialService } from '@/services/materialService'
import MaterialTable from '@/components/materials/MaterialTable.vue'
import MaterialHistory from '@/components/materials/MaterialHistory.vue'
import AssignMaterialModal from '@/components/materials/AssignMaterialModal.vue'
import TransferMaterialModal from '@/components/materials/TransferMaterialModal.vue'
import ReturnMaterialModal from '@/components/materials/ReturnMaterialModal.vue'
import MaterialDetailModal from '@/components/materials/MaterialDetailModal.vue'
const store = useMaterialStore()
const currentTab = ref('user')
const searchBarcode = ref('')
const searchMaterial = ref('')
const selectedUser = ref(null)
const selectedBarcode = ref('')
const currentPage = ref(1)
const perPage = ref(15)
const filterType = ref('')
const assignModal = ref(false)
const transferModal = ref(false)
const returnModal = ref(false)
const detailModal = ref(false)
const saving = ref(false)
const assignForm = reactive({
user_id: null,
barcode_id: '',
material_name: '',
type: 'serialized',
serial_number: '',
qty: 1,
unit: '',
})
const transferForm = reactive({
barcode_id: '',
from_user_id: null,
to_user_id: null,
})
const returnForm = reactive({
barcode_id: '',
user_id: null,
})
const detailItem = ref({})
const filteredMaterials = computed(() => {
return store.materials.filter((item) => {
const barcodeMatch =
!searchBarcode.value ||
item.barcode_id?.toLowerCase().includes(searchBarcode.value.toLowerCase())
const materialMatch =
!searchMaterial.value ||
item.material_name?.toLowerCase().includes(searchMaterial.value.toLowerCase())
const userMatch = !selectedUser.value || item.user_id == selectedUser.value
const typeMatch = !filterType.value || item.type === filterType.value
return barcodeMatch && materialMatch && userMatch && typeMatch
})
})
const isFilteringActive = computed(() => {
return (
searchBarcode.value !== '' ||
searchMaterial.value !== '' ||
selectedUser.value !== null ||
filterType.value !== ''
)
})
const currentMaterialsSource = computed(() => {
return isFilteringActive.value ? filteredMaterials.value : store.materials
})
const totalPages = computed(() => Math.ceil(currentMaterialsSource.value.length / perPage.value))
const paginatedMaterials = computed(() => {
const start = (currentPage.value - 1) * perPage.value
return currentMaterialsSource.value.slice(start, start + perPage.value)
})
const assignedMaterial = computed(
() => store.materials.filter((i) => i.status === 'Assigned').length,
)
const returnedMaterial = computed(
() => store.materials.filter((i) => i.status === 'Returned').length,
)
const serializedMaterial = computed(
() => store.materials.filter((i) => i.type === 'serialized').length,
)
const consumableMaterial = computed(
() => store.materials.filter((i) => i.type === 'consumable').length,
)
const totalMaterial = computed(() => store.materials.length)
watch(searchBarcode, () => {
currentPage.value = 1
})
watch(searchMaterial, () => {
currentPage.value = 1
})
watch(filterType, () => {
currentPage.value = 1
})
watch([selectedUser], async ([newSelectedUser]) => {
currentPage.value = 1
if (newSelectedUser) {
await store.fetchByUser(newSelectedUser)
} else {
await store.fetchAll()
}
})
watch(selectedBarcode, async (val) => {
if (val) await store.fetchHistory(val)
})
onMounted(() => {
store.fetchAll()
})
function openTransferModal(item) {
transferForm.barcode_id = item.barcode_id
transferForm.from_user_id = item.user_id
transferForm.to_user_id = null
transferModal.value = true
}
function openReturnModal(item) {
returnForm.barcode_id = item.barcode_id
returnForm.user_id = item.user_id
returnModal.value = true
}
function openDetail(item) {
detailItem.value = { ...item }
detailModal.value = true
}
async function assignMaterial() {
saving.value = true
try {
await materialService.assign({
...assignForm,
qty: Number(assignForm.qty),
})
assignModal.value = false
Swal.fire({
icon: 'success',
title: 'Berhasil',
text: 'Material berhasil di-assign',
timer: 1500,
showConfirmButton: false,
})
const userId = selectedUser.value || assignForm.user_id
if (userId) {
selectedUser.value = userId
await store.fetchByUser(userId)
} else {
await store.fetchAll()
}
assignForm.barcode_id = ''
assignForm.user_id = null
assignForm.material_name = ''
assignForm.type = 'serialized'
assignForm.serial_number = ''
assignForm.qty = 1
assignForm.unit = ''
} catch (err) {
Swal.fire({ icon: 'error', title: 'Gagal', text: err.response?.data?.message || err.message })
} finally {
saving.value = false
}
}
async function transferMaterial() {
const confirm = await Swal.fire({
title: 'Transfer Material?',
text: 'Pastikan user tujuan sudah benar.',
icon: 'question',
showCancelButton: true,
confirmButtonText: 'Transfer',
cancelButtonText: 'Batal',
})
if (!confirm.isConfirmed) return
saving.value = true
try {
await materialService.transfer({ ...transferForm })
transferModal.value = false
Swal.fire({
icon: 'success',
title: 'Berhasil',
text: 'Material berhasil dipindahkan',
timer: 1500,
showConfirmButton: false,
})
if (selectedUser.value) {
await store.fetchByUser(selectedUser.value)
} else {
await store.fetchAll()
}
if (selectedBarcode.value) await store.fetchHistory(selectedBarcode.value)
} catch (err) {
Swal.fire({ icon: 'error', title: 'Gagal', text: err.response?.data?.message || err.message })
} finally {
saving.value = false
}
}
async function returnMaterial() {
const confirm = await Swal.fire({
title: 'Return Material?',
text: 'Material akan dikembalikan.',
icon: 'warning',
showCancelButton: true,
confirmButtonText: 'Ya',
})
if (!confirm.isConfirmed) return
saving.value = true
try {
await materialService.returnMaterial({ ...returnForm })
returnModal.value = false
Swal.fire({
icon: 'success',
title: 'Berhasil',
text: 'Material berhasil dikembalikan',
timer: 1500,
showConfirmButton: false,
})
if (selectedUser.value) {
await store.fetchByUser(selectedUser.value)
} else {
await store.fetchAll()
}
if (selectedBarcode.value) await store.fetchHistory(selectedBarcode.value)
} catch (err) {
Swal.fire({ icon: 'error', title: 'Gagal', text: err.response?.data?.message || err.message })
} finally {
saving.value = false
}
}
</script>
<template>
<CRow>
<CCol :xs="12">
<CCard class="mb-4">
<CCardHeader class="d-flex justify-content-between align-items-center">
<div>
<strong>Material Management</strong>
<div class="small text-body-secondary">
Assign, Transfer, Return dan History Material
</div>
</div>
<CButton color="primary" @click="assignModal = true">+ Tambah Material</CButton>
</CCardHeader>
<CCardBody>
<CRow class="mb-4">
<CCol md
><CCard class="border-start border-primary border-4"
><CCardBody
><div>Total Material</div>
<h3>{{ totalMaterial }}</h3></CCardBody
></CCard
></CCol
>
<CCol md
><CCard class="border-start border-success border-4"
><CCardBody
><div>Assigned</div>
<h3>{{ assignedMaterial }}</h3></CCardBody
></CCard
></CCol
>
<CCol md
><CCard class="border-start border-secondary border-4"
><CCardBody
><div>Returned</div>
<h3>{{ returnedMaterial }}</h3></CCardBody
></CCard
></CCol
>
<CCol md
><CCard class="border-start border-info border-4"
><CCardBody
><div>Serialized</div>
<h3>{{ serializedMaterial }}</h3></CCardBody
></CCard
></CCol
>
<CCol md
><CCard class="border-start border-warning border-4"
><CCardBody
><div>Consumable</div>
<h3>{{ consumableMaterial }}</h3></CCardBody
></CCard
></CCol
>
</CRow>
<CTabs :active-item-key="currentTab" @change="(key) => (currentTab = key)">
<CTabList variant="tabs">
<CTab item-key="user">Material User</CTab>
<CTab item-key="history">History</CTab>
</CTabList>
<CTabPanel item-key="user" class="mt-4">
<CRow class="mb-3">
<CCol md="3"
><CFormLabel>Barcode</CFormLabel><CFormInput v-model="searchBarcode"
/></CCol>
<CCol md="3"
><CFormLabel>Material</CFormLabel><CFormInput v-model="searchMaterial"
/></CCol>
<CCol md="2">
<CFormLabel>Type</CFormLabel>
<CFormSelect v-model="filterType">
<option value="">Semua Type</option>
<option value="serialized">Serialized</option>
<option value="consumable">Consumable</option>
</CFormSelect>
</CCol>
<CCol md="2">
<CFormLabel>User ID</CFormLabel>
<CFormInput v-model="selectedUser" placeholder="Filter by User ID" />
</CCol>
<CCol md="2" class="d-flex align-items-end">
<CButton
color="secondary"
@click="
((searchBarcode = ''),
(searchMaterial = ''),
(selectedUser = null),
(filterType = ''))
"
>Reset</CButton
>
</CCol>
</CRow>
<MaterialTable
:data="paginatedMaterials"
:totalPages="totalPages"
:currentPage="currentPage"
:perPage="perPage"
:totalItems="currentMaterialsSource.length"
:loading="store.loading"
@update:perPage="
(val) => {
perPage = val
currentPage = 1
}
"
@page="(p) => (currentPage = p)"
@detail="openDetail"
@transfer="openTransferModal"
@return="openReturnModal"
/>
</CTabPanel>
<CTabPanel item-key="history" class="mt-4">
<CRow class="mb-3">
<CCol md="4">
<CFormLabel>Barcode</CFormLabel>
<CFormInput v-model="selectedBarcode" placeholder="Masukkan Barcode" />
</CCol>
<CCol md="2" class="d-flex align-items-end">
<CButton color="primary" @click="store.fetchHistory(selectedBarcode)"
>Lihat History</CButton
>
</CCol>
</CRow>
<MaterialHistory :histories="store.histories" />
</CTabPanel>
</CTabs>
</CCardBody>
</CCard>
</CCol>
</CRow>
<AssignMaterialModal
:visible="assignModal"
:form="assignForm"
:saving="saving"
@close="assignModal = false"
@save="assignMaterial"
/>
<TransferMaterialModal
:visible="transferModal"
:form="transferForm"
:saving="saving"
@close="transferModal = false"
@save="transferMaterial"
/>
<ReturnMaterialModal
:visible="returnModal"
:form="returnForm"
:saving="saving"
@close="returnModal = false"
@save="returnMaterial"
/>
<MaterialDetailModal
:visible="detailModal"
:item="detailItem"
@close="detailModal = false"
@transfer="openTransferModal"
@return="openReturnModal"
/>
</template>