Files
geMoldInsight/frontend/src/modules/inventory/components/InventoryTab.vue
T
2026-06-23 09:38:31 +08:00

179 lines
5.6 KiB
Vue

<script setup lang="ts">
import { reactive, ref, onMounted } from 'vue'
import { useInventory } from '@/modules/inventory/composables/useInventory'
import { apiRequest } from '@/shared/api'
import { addNotification, handleApiError } from '@/shared/notification'
const { state, loadInventory, ensureStockBaseData } = useInventory()
const showModal = ref(false)
const editingItem = ref<any>(null)
const saving = ref(false)
const form = reactive({
product_id: null as number | null,
warehouse_id: null as number | null,
quantity: 0,
locked_quantity: 0,
batch_no: '',
location: ''
})
function openCreate() {
ensureStockBaseData()
editingItem.value = null
form.product_id = null
form.warehouse_id = null
form.quantity = 0
form.locked_quantity = 0
form.batch_no = ''
form.location = ''
showModal.value = true
}
function openEdit(item: any) {
ensureStockBaseData()
editingItem.value = item
form.product_id = item.product_id ?? null
form.warehouse_id = item.warehouse_id ?? null
form.quantity = item.quantity ?? 0
form.locked_quantity = item.locked_quantity ?? 0
form.batch_no = item.batch_no ?? ''
form.location = item.location ?? ''
showModal.value = true
}
async function save() {
if (saving.value) return
if (!form.product_id) {
addNotification('请选择物料', 'warning')
return
}
if (!form.warehouse_id) {
addNotification('请选择仓库', 'warning')
return
}
if (form.quantity < 0) {
addNotification('数量不能为负数', 'warning')
return
}
if (form.locked_quantity > form.quantity) {
addNotification('锁定数量不能大于库存数量', 'warning')
return
}
saving.value = true
try {
const payload = {
product_id: form.product_id,
warehouse_id: form.warehouse_id,
quantity: form.quantity,
locked_quantity: form.locked_quantity,
batch_no: form.batch_no || null,
location: form.location || null
}
if (editingItem.value) {
await apiRequest(`/api/inventory/${editingItem.value.id}`, {
method: 'PUT',
body: JSON.stringify(payload)
})
addNotification('物料库存更新成功', 'success')
} else {
await apiRequest('/api/inventory', {
method: 'POST',
body: JSON.stringify(payload)
})
addNotification('物料库存已创建', 'success')
}
showModal.value = false
loadInventory()
} catch (e) {
handleApiError(e, '保存物料库存')
} finally {
saving.value = false
}
}
async function deleteItem(id: number) {
if (!confirm('确定要删除这个物料库存记录吗?')) return
try {
await apiRequest(`/api/inventory/${id}`, { method: 'DELETE' })
addNotification('物料库存已删除', 'success')
loadInventory()
} catch (e) {
handleApiError(e, '删除物料库存')
}
}
onMounted(() => { loadInventory() })
</script>
<template>
<div class="inventory-tab">
<div class="table-header">
<t-button type="primary" @click="openCreate">+ 新增物料库存</t-button>
</div>
<t-table :data="state.inventory" style="width: 100%" :loading="state.loading" empty-text="暂无库存数据">
<t-table-column prop="product_sku" label="SKU" />
<t-table-column prop="product_name" label="物料" />
<t-table-column prop="warehouse_name" label="仓库" />
<t-table-column prop="quantity" label="数量" />
<t-table-column prop="available_quantity" label="可用" />
<t-table-column label="操作" width="180">
<template #default="{ row }">
<t-button size="small" @click="openEdit(row)">编辑</t-button>
<t-button size="small" type="danger" @click="deleteItem(row.id)">删除</t-button>
</template>
</t-table-column>
</t-table>
<t-dialog v-model="showModal" :title="editingItem ? '编辑物料库存' : '新增物料库存'" width="520px" :close-on-click-modal="false">
<t-form :model="form" label-width="80px">
<t-form-item label="物料" required>
<t-select v-model="form.product_id" placeholder="请选择物料" style="width: 100%">
<t-option
v-for="m in state.materials"
:key="m.id"
:label="m.name + (m.sku ? ' (' + m.sku + ')' : '')"
:value="m.id"
/>
</t-select>
</t-form-item>
<t-form-item label="仓库" required>
<t-select v-model="form.warehouse_id" placeholder="请选择仓库" style="width: 100%">
<t-option
v-for="w in state.warehouses"
:key="w.id"
:label="w.name"
:value="w.id"
/>
</t-select>
</t-form-item>
<t-form-item label="数量" required>
<t-input-number v-model="form.quantity" :min="0" style="width: 100%" />
</t-form-item>
<t-form-item label="锁定数量">
<t-input-number v-model="form.locked_quantity" :min="0" style="width: 100%" />
</t-form-item>
<t-form-item label="批次号">
<t-input v-model="form.batch_no" placeholder="请输入批次号" />
</t-form-item>
<t-form-item label="库位">
<t-input v-model="form.location" placeholder="请输入库位" />
</t-form-item>
</t-form>
<template #footer>
<t-button @click="showModal = false" :disabled="saving">取消</t-button>
<t-button type="primary" :loading="saving" :disabled="saving" @click="save">保存</t-button>
</template>
</t-dialog>
</div>
</template>
<style scoped>
.inventory-tab {
padding: 0;
}
.table-header {
margin-bottom: 16px;
}
</style>