|
|
@@ -129,6 +129,8 @@
|
|
|
<attribute ref="attributeRef" @set-attribute="setAttribute" />
|
|
|
<!-- 商品批次属性-->
|
|
|
<lot-date ref="lotDateRef" @select-lot-date="selectLotDate" />
|
|
|
+ <!-- 组合商品-->
|
|
|
+ <barcode-combine ref="barcodeCombineRef" @setCombine="setCombineReceiving" @cancel="onCombineCancel" :container="containerNo" :matched-sku="combineMatchedSku" />
|
|
|
<!-- 唯一码-->
|
|
|
<unique-code-input ref="uniqueCodeRef"
|
|
|
v-model:uniqueCodeList="uniqueCodeList"
|
|
|
@@ -168,6 +170,7 @@ import {
|
|
|
getReceivingAsnDetails,
|
|
|
setProductAttribute, setReceiving,
|
|
|
} from '@/api/takeDelivery/index'
|
|
|
+import { getListCombineSku } from '@/api/picking'
|
|
|
import { closeLoading, showLoading } from '@/utils/loading'
|
|
|
import { useStore } from '@/store/modules/user'
|
|
|
import { showNotify, showToast } from 'vant'
|
|
|
@@ -175,7 +178,9 @@ import { isAttribute } from '@/views/inbound/takeDelivery/task/hooks/attribute'
|
|
|
import Attribute from '@/views/inbound/takeDelivery/components/Attribute.vue'
|
|
|
import LotDate from '@/views/inbound/takeDelivery/components/LotDate.vue'
|
|
|
import UniqueCodeInput from '@/views/inbound/takeDelivery/components/UniqueCodeInput.vue'
|
|
|
-import { barcodeToUpperCase, toMap } from '@/utils/dataType.js'
|
|
|
+import BarcodeCombine from '@/views/inbound/takeDelivery/components/BarcodeCombine.vue'
|
|
|
+import { receivingBarcodeCombine } from '@/views/inbound/takeDelivery/task/hooks/barcodeCombine'
|
|
|
+import { barcodeToUpperCase, toMap } from '@/utils/dataType'
|
|
|
import { getCurrentTime } from '@/utils/date'
|
|
|
|
|
|
const router = useRouter()
|
|
|
@@ -188,7 +193,7 @@ try {
|
|
|
}
|
|
|
const warehouse = store.warehouse
|
|
|
//开单任务号
|
|
|
-const taskNo = ref('')
|
|
|
+const taskNo = ref('BSSH20260318000003')
|
|
|
//容器号
|
|
|
const containerNo = ref('')
|
|
|
//商品条码
|
|
|
@@ -201,6 +206,8 @@ const taskInfo = ref({ receivedQty: 0, expectedQty: 0 })
|
|
|
const currentTime = ref('--')
|
|
|
const scanType = ref(2)
|
|
|
|
|
|
+//任务号下所有asn单数据
|
|
|
+const allAsnDetailList=ref([])
|
|
|
const type=localStorage.getItem('checkAllType')?JSON.parse(localStorage.getItem('checkAllType')):true
|
|
|
const checkAllType=ref(type)
|
|
|
// 页面初始化
|
|
|
@@ -244,10 +251,9 @@ const stopTimer = () => {
|
|
|
|
|
|
const back = ref(true)
|
|
|
const inputBarcodeType = ref('task')
|
|
|
-//输入框组件
|
|
|
const inputBarcodeRef = ref(null)
|
|
|
const oldSearchBarcode = ref('')
|
|
|
-// 设置容器号
|
|
|
+// 任务号/容器号:code 为任务号时拉取任务及ASN明细
|
|
|
const setBarcode = (code, type) => {
|
|
|
if (inputBarcodeType.value === 'lot') {
|
|
|
lotData.value.forEach((lot) => {
|
|
|
@@ -271,9 +277,6 @@ const setBarcode = (code, type) => {
|
|
|
taskNo.value=''
|
|
|
taskInfo.value={}
|
|
|
switchTask()
|
|
|
- }else {
|
|
|
- taskInfo.value=res.data
|
|
|
- taskNo.value=code
|
|
|
}
|
|
|
containerNo.value=''
|
|
|
stopTimer()
|
|
|
@@ -284,11 +287,15 @@ const setBarcode = (code, type) => {
|
|
|
startTimer()
|
|
|
containerNo.value=''
|
|
|
}
|
|
|
- taskInfo.value=res.data
|
|
|
- taskNo.value=code
|
|
|
}
|
|
|
+ taskInfo.value=res.data
|
|
|
+ taskNo.value=code
|
|
|
scanType.value=2
|
|
|
uniqueCodeList.value=[]
|
|
|
+ const params = { warehouse, asnNos: taskInfo.value?.asnNos.join(',') }
|
|
|
+ getReceivingAsnDetails(params).then(res => {
|
|
|
+ allAsnDetailList.value = res.data
|
|
|
+ })
|
|
|
scanSuccess()
|
|
|
}).catch(err=>{
|
|
|
inputBarcodeRef.value?.show('', '请扫描开单任务号',err.message)
|
|
|
@@ -298,9 +305,8 @@ const setBarcode = (code, type) => {
|
|
|
closeLoading()
|
|
|
})
|
|
|
}
|
|
|
-// setBarcode('BSSH20250605000006')
|
|
|
+setBarcode('BSSH20260318000003')
|
|
|
|
|
|
-//切换任务
|
|
|
const switchTask = () => {
|
|
|
inputBarcodeType.value = 'switchTask'
|
|
|
back.value = false
|
|
|
@@ -318,13 +324,19 @@ const reset = () => {
|
|
|
searchBarcode.value = ''
|
|
|
oldSearchBarcode.value = ''
|
|
|
uniqueCodeList.value = []
|
|
|
+ combineMatchedSku.value = []
|
|
|
+ combineAsnSelectList.value = []
|
|
|
+ isCombineSelectMode.value = false
|
|
|
+ combineReceivingData.value = []
|
|
|
}
|
|
|
-// 选择单据
|
|
|
const onDetailActive = (item) => {
|
|
|
+ if (isCombineSelectMode.value) {
|
|
|
+ _onCombineAsnSelected(item)
|
|
|
+ return
|
|
|
+ }
|
|
|
asnInfo.value = item
|
|
|
asnDetailsTrueFalseBy.value = false
|
|
|
searchCount.value=1
|
|
|
- // searchCount.value = asnInfo.value.expectedQuantity - asnInfo.value.receivedQuantity
|
|
|
_getProductAttribute(item)
|
|
|
_getProductLot(item)
|
|
|
_getCommodityRule(item)
|
|
|
@@ -338,29 +350,104 @@ const onAsnCancel = () => {
|
|
|
}
|
|
|
const uniqueCodeList = ref([])
|
|
|
|
|
|
-// 扫描条码监听
|
|
|
+// 组合商品
|
|
|
+const barcodeCombineRef = ref(null)
|
|
|
+const combineMatchedSku = ref([])
|
|
|
+const combineAsnSelectList = ref([])
|
|
|
+const isCombineSelectMode = ref(false)
|
|
|
+const combineReceivingData = ref([]) // 确认实收数后暂存,完成收货时提交
|
|
|
+
|
|
|
+// 组合商品只支持1个
|
|
|
+const _handleCombineProduct = (code) => {
|
|
|
+ showLoading()
|
|
|
+ getListCombineSku({ combineSku: barcodeToUpperCase(code), workEnvironment: 'receiving' }).then((res) => {
|
|
|
+ const _err = (msg) => { closeLoading(); scanError(); showNotify({ type: 'danger', duration: 3000, message: msg }); reset() }
|
|
|
+ if (!res.data?.length) return _err(`${code}-商品条码不匹配,请重新扫描`)
|
|
|
+ if (res.data.length > 1) return _err('不支持多商品组合商品')
|
|
|
+ const combineData = res.data
|
|
|
+ const matchedList = receivingBarcodeCombine(allAsnDetailList.value, toMap(combineData, 'barcode'))
|
|
|
+ if (!matchedList.length) return _err('组合商品与待收货数据不匹配,请检查组合商品配置!')
|
|
|
+ const asnGroupMap = matchedList.reduce((acc, detail) => {
|
|
|
+ const key = detail.asnNo
|
|
|
+ if (!acc[key]) acc[key] = { asnNo: detail.asnNo, customerId: detail.customerId, expectedQuantity: 0, list: [] }
|
|
|
+ acc[key].list.push(detail)
|
|
|
+ acc[key].expectedQuantity += (detail.expectedQuantity || 0) - (detail.receivedQuantity || 0)
|
|
|
+ return acc
|
|
|
+ }, {})
|
|
|
+ const asnOptions = Object.values(asnGroupMap)
|
|
|
+ if (asnOptions.length > 1) {
|
|
|
+ isCombineSelectMode.value = true
|
|
|
+ combineAsnSelectList.value = asnOptions
|
|
|
+ combineMatchedSku.value = matchedList
|
|
|
+ asnDetailsList.value = asnOptions.map((opt) => ({ asnNo: opt.asnNo, customerId: opt.customerId, expectedQuantity: opt.expectedQuantity }))
|
|
|
+ asnDetailsTrueFalseBy.value = true
|
|
|
+ } else {
|
|
|
+ _showCombineDialog(matchedList)
|
|
|
+ }
|
|
|
+ closeLoading()
|
|
|
+ scanSuccess()
|
|
|
+ }).catch(() => { closeLoading(); scanError() })
|
|
|
+}
|
|
|
+
|
|
|
+const _showCombineDialog = (matchedList) => {
|
|
|
+ combineMatchedSku.value = matchedList
|
|
|
+ asnInfo.value = matchedList[0]
|
|
|
+ _getProductAttribute(matchedList[0])
|
|
|
+ _getProductLot(matchedList[0])
|
|
|
+ _getCommodityRule(matchedList[0])
|
|
|
+ barcodeCombineRef.value?.show()
|
|
|
+}
|
|
|
+
|
|
|
+// 组合商品取消:收货数量=1套总件数
|
|
|
+const onCombineCancel = () => {
|
|
|
+ const total = combineMatchedSku.value.reduce((sum, row) => sum + (row.matchedJson?.quantity || 0), 0)
|
|
|
+ searchCount.value = total ? String(total) : '1'
|
|
|
+ combineReceivingData.value = []
|
|
|
+}
|
|
|
+
|
|
|
+const _onCombineAsnSelected = (item) => {
|
|
|
+ const selected = combineAsnSelectList.value.find((opt) => opt.asnNo === item.asnNo)
|
|
|
+ if (selected?.list) _showCombineDialog(selected.list)
|
|
|
+ asnDetailsTrueFalseBy.value = isCombineSelectMode.value = false
|
|
|
+ combineAsnSelectList.value = []
|
|
|
+}
|
|
|
+
|
|
|
+// 组合商品确认实收数
|
|
|
+const setCombineReceiving = ({ dataList }) => {
|
|
|
+ if (!dataList?.length) return
|
|
|
+ const total = dataList.reduce((sum, row) => sum + (row.quantity || 0), 0)
|
|
|
+ searchCount.value = String(total)
|
|
|
+ combineReceivingData.value = dataList
|
|
|
+ showNotify({ type: 'success', duration: 2000, message: `已填入收货数量:${total},请点击完成收货提交` })
|
|
|
+}
|
|
|
+
|
|
|
+// 条码扫描:scanType 2商品/4数量/3唯一码/5容器
|
|
|
const _handlerScan = (code) => {
|
|
|
if (scanType.value == 2) {
|
|
|
searchBarcode.value = code
|
|
|
oldSearchBarcode.value = code
|
|
|
- const params = { warehouse, barcode: code, asnNos: taskInfo.value?.asnNos.join(',') }
|
|
|
- showLoading()
|
|
|
- getReceivingAsnDetails(params).then(res => {
|
|
|
+ if ( allAsnDetailList.value.length > 0) {
|
|
|
+ const upperCode = barcodeToUpperCase(code) || ''
|
|
|
+ const clientMatched = allAsnDetailList.value.filter((detail) => {
|
|
|
+ const bars = [detail.barcode, detail.barcode2, detail.sku].filter(Boolean)
|
|
|
+ return bars.some((bar) => bar && barcodeToUpperCase(bar) === upperCode)
|
|
|
+ })
|
|
|
+ asnDetailsList.value = clientMatched
|
|
|
+ }
|
|
|
uniqueCodeList.value=[]
|
|
|
- asnDetailsList.value = res.data
|
|
|
- if (res.data.length > 0) {
|
|
|
+
|
|
|
+ if (asnDetailsList.value.length > 0) {
|
|
|
scanSuccess()
|
|
|
closeLoading()
|
|
|
- if (res.data.length == 1) {
|
|
|
- const item = res.data[0]
|
|
|
+ if (asnDetailsList.value.length == 1) {
|
|
|
+ const item = asnDetailsList.value[0]
|
|
|
asnInfo.value = item
|
|
|
- // searchCount.value = item.expectedQuantity - item.receivedQuantity
|
|
|
- searchCount.value=1
|
|
|
+ searchCount.value = 1
|
|
|
_getProductAttribute(item)
|
|
|
_getProductLot(item)
|
|
|
_getCommodityRule(item)
|
|
|
}
|
|
|
- if (res.data.length > 1) {
|
|
|
+ if (asnDetailsList.value.length > 1) {
|
|
|
asnInfo.value = {}
|
|
|
lotData.value = []
|
|
|
searchCount.value = ''
|
|
|
@@ -368,21 +455,14 @@ const _handlerScan = (code) => {
|
|
|
asnDetailsTrueFalseBy.value = true
|
|
|
}
|
|
|
} else {
|
|
|
- scanError()
|
|
|
- showNotify({ type: 'danger', duration: 3000, message: `暂未查询到条码《${code}》信息请重试` })
|
|
|
- reset()
|
|
|
- closeLoading()
|
|
|
+ _handleCombineProduct(code)
|
|
|
}
|
|
|
- }).catch(() => {
|
|
|
- scanError()
|
|
|
- closeLoading()
|
|
|
- })
|
|
|
} else if (scanType.value == 3) {
|
|
|
if (code) {
|
|
|
const uniqueCodeScanType = uniqueCodeRef.value?.uniqueCodeScanType
|
|
|
if (checkAllType.value && uniqueCodeScanType === 'barcode') {
|
|
|
const barcode = Array.from(new Set([asnInfo.value.barcode, asnInfo.value.barcode2, asnInfo.value.sku].filter(Boolean)));
|
|
|
- if (barcode.some(item => barcodeToUpperCase(item) === barcodeToUpperCase(code))) {
|
|
|
+ if (barcode.some((bar) => barcodeToUpperCase(bar) === barcodeToUpperCase(code))) {
|
|
|
scanSuccess();
|
|
|
uniqueCodeRef.value.uniqueCodeScanType = 'unique'
|
|
|
uniqueCodeRef.value.uniqueBarcode = code
|
|
|
@@ -428,9 +508,7 @@ const _handlerScan = (code) => {
|
|
|
scanType.value=2
|
|
|
}
|
|
|
}
|
|
|
-/**
|
|
|
- * 物理属性
|
|
|
- */
|
|
|
+// 物理属性
|
|
|
const attributeRef = ref(null)
|
|
|
const attributeMap = ref({})
|
|
|
const attributeTrueFalseBy = ref(true)
|
|
|
@@ -461,14 +539,8 @@ const setAttribute = (data) => {
|
|
|
scanError()
|
|
|
})
|
|
|
}
|
|
|
-/**
|
|
|
- * 物理属性 end
|
|
|
- */
|
|
|
|
|
|
-/**
|
|
|
- * 商品批次属性
|
|
|
- */
|
|
|
-// 获取商品批次属性
|
|
|
+// 批次属性
|
|
|
const lotData = ref([])
|
|
|
const _getProductLot = (item) => {
|
|
|
const params = { warehouse: item.warehouse, owner: item.customerId, barcode: item.sku }
|
|
|
@@ -574,12 +646,7 @@ const selectLotDate = (date) => {
|
|
|
inputBarcodeType.value = 'task'
|
|
|
}
|
|
|
|
|
|
-/**
|
|
|
- * 商品批次属性end
|
|
|
- */
|
|
|
-/**
|
|
|
- * 唯一码
|
|
|
- */
|
|
|
+// 唯一码
|
|
|
const uniqueCodeRef = ref(null)
|
|
|
//规则列表
|
|
|
const uniqueRuleList = ref([])
|
|
|
@@ -599,12 +666,9 @@ const _getCommodityRule = (item) => {
|
|
|
uniqueRuleMap.value = toMap(res.data, 'type', 'uniqueRegExp')
|
|
|
})
|
|
|
}
|
|
|
-/**
|
|
|
- * 唯一码end
|
|
|
- */
|
|
|
const containerNoRef = ref(null)
|
|
|
const numberRef = ref(null)
|
|
|
-// 完成收货校验
|
|
|
+// 完成收货前校验
|
|
|
const isCheck = () => {
|
|
|
if (!asnInfo.value.asnNo) {
|
|
|
scanError()
|
|
|
@@ -680,7 +744,7 @@ const isCheck = () => {
|
|
|
}
|
|
|
return true
|
|
|
}
|
|
|
-// 收货
|
|
|
+// 完成收货
|
|
|
const onConfirm = () => {
|
|
|
if(isCheck()){
|
|
|
const lotMap = toMap(lotData.value, 'field', 'mapping')
|
|
|
@@ -723,9 +787,6 @@ const loadData = () => {
|
|
|
if (!taskNo.value) {
|
|
|
inputBarcodeRef.value?.show('', '请扫描开单任务号','')
|
|
|
return
|
|
|
- } else {
|
|
|
- // currentTime.value=getCurrentTime()
|
|
|
- // startTimer()
|
|
|
}
|
|
|
}
|
|
|
onUnmounted(() => {
|