|
|
|
|
@ -277,6 +277,8 @@ interface StockItem {
|
|
|
|
|
type?: string
|
|
|
|
|
category?: string
|
|
|
|
|
price?: number
|
|
|
|
|
source_table?: string
|
|
|
|
|
stock_id?: number
|
|
|
|
|
[key: string]: any
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@ -293,6 +295,7 @@ const showQtyDialog = ref(false)
|
|
|
|
|
|
|
|
|
|
const allData = ref<StockItem[]>([])
|
|
|
|
|
const scannedMap = ref<Map<string, number>>(new Map())
|
|
|
|
|
const borrowedQuantities = ref<Record<string, number>>({})
|
|
|
|
|
|
|
|
|
|
const filterType = ref('all')
|
|
|
|
|
const searchKeyword = ref('')
|
|
|
|
|
@ -307,6 +310,34 @@ const api = {
|
|
|
|
|
clearDraft: () => request({ url: '/v1/inbound/stock/draft/clear', method: 'post', data: { user_id: currentUser } })
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const typeToSourceTable = (type: string): string => {
|
|
|
|
|
switch (type) {
|
|
|
|
|
case 'material': return 'stock_buy'
|
|
|
|
|
case 'semi': return 'stock_semi'
|
|
|
|
|
case 'product': return 'stock_product'
|
|
|
|
|
default: return ''
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async function fetchBorrowedQuantities(items: StockItem[]): Promise<void> {
|
|
|
|
|
const payload = items.filter(i => i.source_table && i.stock_id).map(i => ({
|
|
|
|
|
source_table: i.source_table,
|
|
|
|
|
stock_id: i.stock_id
|
|
|
|
|
}))
|
|
|
|
|
if (payload.length === 0) return
|
|
|
|
|
try {
|
|
|
|
|
const res = await request({
|
|
|
|
|
url: '/v1/inbound/stock/borrowed-quantities',
|
|
|
|
|
method: 'post',
|
|
|
|
|
data: { items: payload }
|
|
|
|
|
})
|
|
|
|
|
// res is map of key->qty
|
|
|
|
|
borrowedQuantities.value = { ...borrowedQuantities.value, ...res }
|
|
|
|
|
} catch (e) {
|
|
|
|
|
console.error('获取借出数量失败', e)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
onMounted(async () => {
|
|
|
|
|
await checkServerDraft()
|
|
|
|
|
})
|
|
|
|
|
@ -381,7 +412,9 @@ const loadData = async () => {
|
|
|
|
|
qty_stock: stock,
|
|
|
|
|
qty_actual: isScanned ? scannedMap.value.get(uuid)! : 0,
|
|
|
|
|
scanned: isScanned,
|
|
|
|
|
uniqueKey: `${type}_${item.id}`
|
|
|
|
|
uniqueKey: `${type}_${item.id}`,
|
|
|
|
|
source_table: typeToSourceTable(type),
|
|
|
|
|
stock_id: item.id
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@ -390,6 +423,7 @@ const loadData = async () => {
|
|
|
|
|
if (res.products) res.products.forEach((i: any) => processItem(i, 'product'))
|
|
|
|
|
|
|
|
|
|
allData.value = list
|
|
|
|
|
await fetchBorrowedQuantities(list)
|
|
|
|
|
} catch (e) {
|
|
|
|
|
ElMessage.error('数据加载失败')
|
|
|
|
|
} finally { loading.value = false }
|
|
|
|
|
@ -471,34 +505,47 @@ const closeOverlays = () => {
|
|
|
|
|
const exportToExcel = () => {
|
|
|
|
|
try {
|
|
|
|
|
// 1. 已盘点 Sheet
|
|
|
|
|
const scannedData = allData.value.filter(i => i.scanned).map(item => ({
|
|
|
|
|
'物品名称': item.name,
|
|
|
|
|
'类型': item.type || item.material_type || '-',
|
|
|
|
|
'类别': item.category || '-',
|
|
|
|
|
'规格型号': item.spec_model || item.standard || '-', // ★ 双重保险
|
|
|
|
|
'SKU': item.sku,
|
|
|
|
|
'批次/SN': item.serial_number || item.batch_no || '-',
|
|
|
|
|
'单位': item.unit || '个',
|
|
|
|
|
'单价': item.price || item.unit_price || 0,
|
|
|
|
|
'账面库存': parseFloat(item.qty_stock as any),
|
|
|
|
|
'实盘数量': item.qty_actual,
|
|
|
|
|
'盘点结果': item.qty_stock === item.qty_actual ? '相符' : '差异',
|
|
|
|
|
'差异数': item.qty_actual - item.qty_stock
|
|
|
|
|
}))
|
|
|
|
|
const scannedData = allData.value.filter(i => i.scanned).map(item => {
|
|
|
|
|
const key = item.source_table && item.stock_id ? `${item.source_table}_${item.stock_id}` : ''
|
|
|
|
|
const borrowedQty = borrowedQuantities.value[key] || 0
|
|
|
|
|
const actualTotal = item.qty_actual + borrowedQty
|
|
|
|
|
const diff = actualTotal - item.qty_stock
|
|
|
|
|
const result = diff === 0 ? '正常' : diff < 0 ? '盘亏/差异' : '盘盈'
|
|
|
|
|
return {
|
|
|
|
|
'物品名称': item.name,
|
|
|
|
|
'类型': item.type || item.material_type || '-',
|
|
|
|
|
'类别': item.category || '-',
|
|
|
|
|
'规格型号': item.spec_model || item.standard || '-', // ★ 双重保险
|
|
|
|
|
'SKU': item.sku,
|
|
|
|
|
'批次/SN': item.serial_number || item.batch_no || '-',
|
|
|
|
|
'单位': item.unit || '个',
|
|
|
|
|
'单价': item.price || item.unit_price || 0,
|
|
|
|
|
'账面库存': parseFloat(item.qty_stock as any),
|
|
|
|
|
'实盘数量': item.qty_actual,
|
|
|
|
|
'借出未还数量': borrowedQty,
|
|
|
|
|
'盘点结果': result,
|
|
|
|
|
'差异数': diff
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
// 2. 未盘点 Sheet
|
|
|
|
|
const missingData = allData.value.filter(i => !i.scanned).map(item => ({
|
|
|
|
|
'物品名称': item.name,
|
|
|
|
|
'类型': item.type || item.material_type || '-',
|
|
|
|
|
'类别': item.category || '-',
|
|
|
|
|
'规格型号': item.spec_model || item.standard || '-', // ★ 双重保险
|
|
|
|
|
'SKU': item.sku,
|
|
|
|
|
'批次/SN': item.serial_number || item.batch_no || '-',
|
|
|
|
|
'单位': item.unit || '个',
|
|
|
|
|
'单价': item.price || item.unit_price || 0,
|
|
|
|
|
'账面库存': parseFloat(item.qty_stock as any),
|
|
|
|
|
'状态': '未盘点'
|
|
|
|
|
}))
|
|
|
|
|
const missingData = allData.value.filter(i => !i.scanned).map(item => {
|
|
|
|
|
const key = item.source_table && item.stock_id ? `${item.source_table}_${item.stock_id}` : ''
|
|
|
|
|
const borrowedQty = borrowedQuantities.value[key] || 0
|
|
|
|
|
return {
|
|
|
|
|
'物品名称': item.name,
|
|
|
|
|
'类型': item.type || item.material_type || '-',
|
|
|
|
|
'类别': item.category || '-',
|
|
|
|
|
'规格型号': item.spec_model || item.standard || '-', // ★ 双重保险
|
|
|
|
|
'SKU': item.sku,
|
|
|
|
|
'批次/SN': item.serial_number || item.batch_no || '-',
|
|
|
|
|
'单位': item.unit || '个',
|
|
|
|
|
'单价': item.price || item.unit_price || 0,
|
|
|
|
|
'账面库存': parseFloat(item.qty_stock as any),
|
|
|
|
|
'借出未还数量': borrowedQty,
|
|
|
|
|
'状态': '未盘点'
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
const wb = XLSX.utils.book_new()
|
|
|
|
|
const ws1 = XLSX.utils.json_to_sheet(scannedData)
|
|
|
|
|
@ -507,7 +554,7 @@ const exportToExcel = () => {
|
|
|
|
|
const wscols = [
|
|
|
|
|
{wch: 20}, {wch: 10}, {wch: 10}, {wch: 15},
|
|
|
|
|
{wch: 15}, {wch: 15}, {wch: 5}, {wch: 8},
|
|
|
|
|
{wch: 8}, {wch: 8}, {wch: 8}, {wch: 8}
|
|
|
|
|
{wch: 8}, {wch: 8}, {wch: 8}, {wch: 8}, {wch: 8}
|
|
|
|
|
]
|
|
|
|
|
ws1['!cols'] = wscols
|
|
|
|
|
ws2['!cols'] = wscols
|
|
|
|
|
|