|
@@ -18,7 +18,7 @@
|
|
|
<div class="info-table">
|
|
<div class="info-table">
|
|
|
<div class="table-row">
|
|
<div class="table-row">
|
|
|
<div class="cell label">源库位</div>
|
|
<div class="cell label">源库位</div>
|
|
|
- <div class="cell value input-cell">
|
|
|
|
|
|
|
+ <div class="cell value input-cell source-location-cell">
|
|
|
<van-search
|
|
<van-search
|
|
|
ref="sourceLocationInputRef"
|
|
ref="sourceLocationInputRef"
|
|
|
v-model.lazy="sourceLocation"
|
|
v-model.lazy="sourceLocation"
|
|
@@ -68,7 +68,7 @@
|
|
|
</div>
|
|
</div>
|
|
|
<div class="table-row">
|
|
<div class="table-row">
|
|
|
<div class="cell label">目标库位</div>
|
|
<div class="cell label">目标库位</div>
|
|
|
- <div class="cell value input-cell input-wide">
|
|
|
|
|
|
|
+ <div class="cell value input-cell input-wide source-location-cell">
|
|
|
<van-search
|
|
<van-search
|
|
|
ref="targetLocationInputRef"
|
|
ref="targetLocationInputRef"
|
|
|
v-model.lazy="productInfo.targetLocationNew"
|
|
v-model.lazy="productInfo.targetLocationNew"
|
|
@@ -84,7 +84,7 @@
|
|
|
<div class="cell value editable" @dblclick="editMoveQty">
|
|
<div class="cell value editable" @dblclick="editMoveQty">
|
|
|
<template v-if="isEditingMoveQty">
|
|
<template v-if="isEditingMoveQty">
|
|
|
<van-field
|
|
<van-field
|
|
|
- v-model="productInfo.moveQty"
|
|
|
|
|
|
|
+ v-model="productInfo.actualMoveQty"
|
|
|
type="number"
|
|
type="number"
|
|
|
autofocus
|
|
autofocus
|
|
|
@blur="confirmMoveQty"
|
|
@blur="confirmMoveQty"
|
|
@@ -92,8 +92,8 @@
|
|
|
/>
|
|
/>
|
|
|
</template>
|
|
</template>
|
|
|
<template v-else>
|
|
<template v-else>
|
|
|
- <span>{{ productInfo.moveQty }}</span>
|
|
|
|
|
- <span v-if="!productInfo.moveQty" class="placeholder">双击编辑</span>
|
|
|
|
|
|
|
+ <span>{{ productInfo.actualMoveQty }}</span>
|
|
|
|
|
+ <span class="placeholder">双击编辑</span>
|
|
|
</template>
|
|
</template>
|
|
|
</div>
|
|
</div>
|
|
|
</div>
|
|
</div>
|
|
@@ -391,8 +391,7 @@ const onBarcodeEnter = async () => {
|
|
|
const params = {
|
|
const params = {
|
|
|
warehouse,
|
|
warehouse,
|
|
|
barcode: scanBarcode.value,
|
|
barcode: scanBarcode.value,
|
|
|
- location: sourceLocation.value,
|
|
|
|
|
- locationRegexp: '^(?!STAGE_|SORTATION_).*$'
|
|
|
|
|
|
|
+ location: sourceLocation.value
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
const res = await getInventory(params)
|
|
const res = await getInventory(params)
|
|
@@ -412,7 +411,13 @@ const onBarcodeEnter = async () => {
|
|
|
productInfo.batchNo = inventoryData.lotNumber
|
|
productInfo.batchNo = inventoryData.lotNumber
|
|
|
productInfo.productionDate = inventoryData.lotAtt01
|
|
productInfo.productionDate = inventoryData.lotAtt01
|
|
|
productInfo.expiryDate = inventoryData.lotAtt02
|
|
productInfo.expiryDate = inventoryData.lotAtt02
|
|
|
- productInfo.moveQty = inventoryData.quantityAvailable + inventoryData.quantityAvailable
|
|
|
|
|
|
|
+ // 可移库数量
|
|
|
|
|
+ const availableQty = inventoryData.quantityAvailable || 0
|
|
|
|
|
+ productInfo.moveQty = availableQty
|
|
|
|
|
+ // 计算推荐移库数量:取可移库数量和任务推荐数量的最小值
|
|
|
|
|
+ const taskRecommendQty = getTaskRecommendQty(sourceLocation.value)
|
|
|
|
|
+ productInfo.recommendMoveQty = taskRecommendQty > 0 ? Math.min(availableQty, taskRecommendQty) : availableQty
|
|
|
|
|
+ productInfo.actualMoveQty = '' // 用户实际填写数量初始为空
|
|
|
|
|
|
|
|
scanSuccess()
|
|
scanSuccess()
|
|
|
showToast('商品信息获取成功')
|
|
showToast('商品信息获取成功')
|
|
@@ -452,6 +457,7 @@ const resetExceptBoxCode = () => {
|
|
|
scanBarcode.value = ''
|
|
scanBarcode.value = ''
|
|
|
selectedBox.value = null
|
|
selectedBox.value = null
|
|
|
resetProductInfo()
|
|
resetProductInfo()
|
|
|
|
|
+ productInfo.targetLocationNew = '' // 清空目标库位
|
|
|
scanType.value = 2
|
|
scanType.value = 2
|
|
|
focusSourceLocationInput()
|
|
focusSourceLocationInput()
|
|
|
}
|
|
}
|
|
@@ -470,6 +476,8 @@ const resetProductInfo = () => {
|
|
|
productInfo.productionDate = ''
|
|
productInfo.productionDate = ''
|
|
|
productInfo.expiryDate = ''
|
|
productInfo.expiryDate = ''
|
|
|
productInfo.moveQty = ''
|
|
productInfo.moveQty = ''
|
|
|
|
|
+ productInfo.recommendMoveQty = ''
|
|
|
|
|
+ productInfo.actualMoveQty = ''
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
// 加载料箱数据
|
|
// 加载料箱数据
|
|
@@ -605,7 +613,9 @@ const productInfo = reactive({
|
|
|
batchNo: '',
|
|
batchNo: '',
|
|
|
productionDate: '',
|
|
productionDate: '',
|
|
|
expiryDate: '',
|
|
expiryDate: '',
|
|
|
- moveQty: '',
|
|
|
|
|
|
|
+ moveQty: '', // 可移库数量(库存可用数量)
|
|
|
|
|
+ recommendMoveQty: '', // 推荐移库数量(取可移库数量和任务推荐数量的最小值)
|
|
|
|
|
+ actualMoveQty: '', // 用户实际填写的移库数量
|
|
|
targetLocationNew: ''
|
|
targetLocationNew: ''
|
|
|
})
|
|
})
|
|
|
|
|
|
|
@@ -969,15 +979,22 @@ const selectSubLocation = (station: StationItem, sub: SubLocation) => {
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
// 确认选择库位
|
|
// 确认选择库位
|
|
|
-const confirmSelectLocation = () => {
|
|
|
|
|
|
|
+const confirmSelectLocation = async () => {
|
|
|
if (currentLocation.recommendType === 'clear') {
|
|
if (currentLocation.recommendType === 'clear') {
|
|
|
// 推荐清空库位,填入源库位
|
|
// 推荐清空库位,填入源库位
|
|
|
sourceLocation.value = currentLocation.id
|
|
sourceLocation.value = currentLocation.id
|
|
|
showLocationPopup.value = false
|
|
showLocationPopup.value = false
|
|
|
showToast(`已选择源库位: ${currentLocation.id}`)
|
|
showToast(`已选择源库位: ${currentLocation.id}`)
|
|
|
- // 切换到扫描商品条码
|
|
|
|
|
- scanType.value = 3
|
|
|
|
|
- focusBarcodeInput()
|
|
|
|
|
|
|
+
|
|
|
|
|
+ // 如果有SKU,自动查询库存信息
|
|
|
|
|
+ if (currentLocation.sku) {
|
|
|
|
|
+ scanBarcode.value = currentLocation.sku
|
|
|
|
|
+ await queryInventoryBySku(currentLocation.sku, currentLocation.id)
|
|
|
|
|
+ } else {
|
|
|
|
|
+ // 切换到扫描商品条码
|
|
|
|
|
+ scanType.value = 3
|
|
|
|
|
+ focusBarcodeInput()
|
|
|
|
|
+ }
|
|
|
} else {
|
|
} else {
|
|
|
// 推荐保留库位,填入目标库位
|
|
// 推荐保留库位,填入目标库位
|
|
|
productInfo.targetLocationNew = currentLocation.id
|
|
productInfo.targetLocationNew = currentLocation.id
|
|
@@ -986,6 +1003,79 @@ const confirmSelectLocation = () => {
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+// 根据SKU查询库存信息
|
|
|
|
|
+const queryInventoryBySku = async (sku: string, location: string) => {
|
|
|
|
|
+ try {
|
|
|
|
|
+ showLoadingToast({ message: '查询中...', forbidClick: true })
|
|
|
|
|
+
|
|
|
|
|
+ const params = {
|
|
|
|
|
+ warehouse,
|
|
|
|
|
+ barcode: sku,
|
|
|
|
|
+ location: location
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ const res = await getInventory(params)
|
|
|
|
|
+ closeToast()
|
|
|
|
|
+
|
|
|
|
|
+ if (res.data && res.data.length > 0) {
|
|
|
|
|
+ const inventoryData = res.data[0]
|
|
|
|
|
+ // 保存完整的库存数据
|
|
|
|
|
+ currentInventoryData.value = inventoryData
|
|
|
|
|
+ // 填充商品信息
|
|
|
|
|
+ productInfo.targetLocation = location
|
|
|
|
|
+ productInfo.stockQty = inventoryData.quantity
|
|
|
|
|
+ productInfo.productName = inventoryData.productName
|
|
|
|
|
+ productInfo.barcode = inventoryData.barcode || inventoryData.barcode2
|
|
|
|
|
+ productInfo.qualityStatus = inventoryData.lotAtt08
|
|
|
|
|
+ productInfo.warehouseType = inventoryData.lotAtt05
|
|
|
|
|
+ productInfo.batchNo = inventoryData.lotNumber
|
|
|
|
|
+ productInfo.productionDate = inventoryData.lotAtt01
|
|
|
|
|
+ productInfo.expiryDate = inventoryData.lotAtt02
|
|
|
|
|
+ // 可移库数量
|
|
|
|
|
+ const availableQty = inventoryData.quantityAvailable || 0
|
|
|
|
|
+ productInfo.moveQty = availableQty
|
|
|
|
|
+ // 计算推荐移库数量:取可移库数量和任务推荐数量的最小值
|
|
|
|
|
+ const taskRecommendQty = getTaskRecommendQty(location)
|
|
|
|
|
+ productInfo.recommendMoveQty = taskRecommendQty > 0 ? Math.min(availableQty, taskRecommendQty) : availableQty
|
|
|
|
|
+ productInfo.actualMoveQty = '' // 用户实际填写数量初始为空
|
|
|
|
|
+
|
|
|
|
|
+ scanSuccess()
|
|
|
|
|
+ showToast('商品信息获取成功')
|
|
|
|
|
+ // 切换到扫描目标库位
|
|
|
|
|
+ scanType.value = 4
|
|
|
|
|
+ focusTargetLocationInput()
|
|
|
|
|
+ } else {
|
|
|
|
|
+ scanError()
|
|
|
|
|
+ showToast('未找到库存信息')
|
|
|
|
|
+ currentInventoryData.value = null
|
|
|
|
|
+ resetProductInfo()
|
|
|
|
|
+ // 切换到扫描商品条码
|
|
|
|
|
+ scanType.value = 3
|
|
|
|
|
+ focusBarcodeInput()
|
|
|
|
|
+ }
|
|
|
|
|
+ } catch (error: any) {
|
|
|
|
|
+ closeToast()
|
|
|
|
|
+ scanError()
|
|
|
|
|
+ showToast(error.message || '查询失败')
|
|
|
|
|
+ // 切换到扫描商品条码
|
|
|
|
|
+ scanType.value = 3
|
|
|
|
|
+ focusBarcodeInput()
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+// 获取任务推荐移库数量(从mergeDetails中获取对应源库位的moveQty)
|
|
|
|
|
+const getTaskRecommendQty = (location: string): number => {
|
|
|
|
|
+ let totalQty = 0
|
|
|
|
|
+ mergeDataList.value.forEach(boxDetail => {
|
|
|
|
|
+ boxDetail.mergeDetails?.forEach((detail: LocationMergeDetails) => {
|
|
|
|
|
+ if (detail.sourceLocation === location && detail.moveQty) {
|
|
|
|
|
+ totalQty += detail.moveQty
|
|
|
|
|
+ }
|
|
|
|
|
+ })
|
|
|
|
|
+ })
|
|
|
|
|
+ return totalQty
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
// 呼唤机器人
|
|
// 呼唤机器人
|
|
|
const callRobot = async () => {
|
|
const callRobot = async () => {
|
|
|
try {
|
|
try {
|
|
@@ -1030,20 +1120,20 @@ const submitMove = () => {
|
|
|
showToast('请先选择目标库位')
|
|
showToast('请先选择目标库位')
|
|
|
return
|
|
return
|
|
|
}
|
|
}
|
|
|
- if (!productInfo.moveQty || Number(productInfo.moveQty) <= 0) {
|
|
|
|
|
|
|
+ if (!productInfo.actualMoveQty || Number(productInfo.actualMoveQty) <= 0) {
|
|
|
scanError()
|
|
scanError()
|
|
|
showToast('请输入有效的移库数量')
|
|
showToast('请输入有效的移库数量')
|
|
|
return
|
|
return
|
|
|
}
|
|
}
|
|
|
- if (Number(productInfo.moveQty) > Number(productInfo.stockQty)) {
|
|
|
|
|
|
|
+ if (Number(productInfo.actualMoveQty) > Number(productInfo.moveQty)) {
|
|
|
scanError()
|
|
scanError()
|
|
|
- showToast('移库数量不能大于库存数量')
|
|
|
|
|
|
|
+ showToast('移库数量不能大于可移库数量')
|
|
|
return
|
|
return
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
showConfirmDialog({
|
|
showConfirmDialog({
|
|
|
title: '移库确认',
|
|
title: '移库确认',
|
|
|
- message: `${productInfo.barcode}从"${sourceLocation.value}"移动至"${productInfo.targetLocationNew}"共:${productInfo.moveQty}件`
|
|
|
|
|
|
|
+ message: `${productInfo.barcode}从"${sourceLocation.value}"移动至"${productInfo.targetLocationNew}"共:${productInfo.actualMoveQty}件`
|
|
|
})
|
|
})
|
|
|
.then(() => {
|
|
.then(() => {
|
|
|
const { traceId, lotNum, lotNumber, ownerCode, owner, sku } = currentInventoryData.value || {}
|
|
const { traceId, lotNum, lotNumber, ownerCode, owner, sku } = currentInventoryData.value || {}
|
|
@@ -1054,7 +1144,7 @@ const submitMove = () => {
|
|
|
sku: sku || productInfo.barcode,
|
|
sku: sku || productInfo.barcode,
|
|
|
lotNum: lotNum || lotNumber || productInfo.batchNo || '',
|
|
lotNum: lotNum || lotNumber || productInfo.batchNo || '',
|
|
|
warehouse,
|
|
warehouse,
|
|
|
- quantity: Number(productInfo.moveQty),
|
|
|
|
|
|
|
+ quantity: Number(productInfo.actualMoveQty),
|
|
|
toLocation: productInfo.targetLocationNew
|
|
toLocation: productInfo.targetLocationNew
|
|
|
}
|
|
}
|
|
|
showLoadingToast({ message: '提交中...', forbidClick: true })
|
|
showLoadingToast({ message: '提交中...', forbidClick: true })
|
|
@@ -1173,6 +1263,10 @@ const submitMove = () => {
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+ &.source-location-cell {
|
|
|
|
|
+ flex: 2;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
&.editable {
|
|
&.editable {
|
|
|
cursor: pointer;
|
|
cursor: pointer;
|
|
|
min-height: 20px;
|
|
min-height: 20px;
|