|
@@ -68,10 +68,15 @@
|
|
|
</tr>
|
|
</tr>
|
|
|
</thead>
|
|
</thead>
|
|
|
<tbody>
|
|
<tbody>
|
|
|
- <tr v-for="(item, index) in locationActive" :key="index" v-if="locationActive.length>0">
|
|
|
|
|
- <td>{{ item.location }}</td>
|
|
|
|
|
- <td>{{ locationType[item.type] || item.type }}</td>
|
|
|
|
|
- <td>{{ item.quantity || 0 }}</td>
|
|
|
|
|
|
|
+ <tr
|
|
|
|
|
+ v-for="(item, index) in locationActive"
|
|
|
|
|
+ :key="index"
|
|
|
|
|
+ v-if="locationActive.length>0"
|
|
|
|
|
+ :class="systemForcePublishEnabled && item.displayType && `display-type--${item.displayType.toLowerCase()}`"
|
|
|
|
|
+ >
|
|
|
|
|
+ <td>{{ systemForcePublishEnabled ? (item.locationId || item.location) : item.location }}</td>
|
|
|
|
|
+ <td>{{ systemForcePublishEnabled ? (locationType[item.locationUsage] || item.locationUsage) : (locationType[item.type] || item.type) }}</td>
|
|
|
|
|
+ <td>{{ systemForcePublishEnabled ? (item.qty || 0) : (item.quantity || 0) }}</td>
|
|
|
<td>
|
|
<td>
|
|
|
<!-- <van-button type="primary" plain size="mini" style="width:100%" @click="setLocation(item)" v-if="!locationActive.location">选择</van-button>-->
|
|
<!-- <van-button type="primary" plain size="mini" style="width:100%" @click="setLocation(item)" v-if="!locationActive.location">选择</van-button>-->
|
|
|
<div>
|
|
<div>
|
|
@@ -91,16 +96,15 @@
|
|
|
<!-- 条码输入组件 -->
|
|
<!-- 条码输入组件 -->
|
|
|
<input-barcode :back="back" @setBarcode="setBarcode" ref="inputBarcodeRef" />
|
|
<input-barcode :back="back" @setBarcode="setBarcode" ref="inputBarcodeRef" />
|
|
|
<!-- 单据选择-->
|
|
<!-- 单据选择-->
|
|
|
- <van-action-sheet v-model:show="lotBarcodeTrueFalseBy" cancel-text="取消" description="请选择商品批次"
|
|
|
|
|
|
|
+ <van-action-sheet v-model:show="lotBarcodeTrueFalseBy" cancel-text="取消" description="请选择具体单据"
|
|
|
close-on-click-action>
|
|
close-on-click-action>
|
|
|
<van-cell-group>
|
|
<van-cell-group>
|
|
|
- <van-cell v-for="item in lotBarcodeList"
|
|
|
|
|
- @click="_getRecommendedLocation(item.lotNumber,item.owner);barcodeActive=item;lotBarcodeTrueFalseBy=false">
|
|
|
|
|
|
|
+ <van-cell v-for="item in lotBarcodeList" @click="onDetailActive(item)">
|
|
|
<template #title>
|
|
<template #title>
|
|
|
- {{ item.barcode }}({{ item.quantity }}件)
|
|
|
|
|
|
|
+ {{ item[0].barcode }}({{ item[0].lotNumber }}-{{ barcodeQuantity(item) }}件)
|
|
|
</template>
|
|
</template>
|
|
|
<template #label>
|
|
<template #label>
|
|
|
- 生产日期:{{ item.lotAtt01 || '--' }}-失效日期:{{ item.lotAtt02 || '--' }}
|
|
|
|
|
|
|
+ 生产日期:{{ item[0].lotAtt01 || '--' }}-失效日期:{{ item[0].lotAtt02 || '--' }}
|
|
|
</template>
|
|
</template>
|
|
|
</van-cell>
|
|
</van-cell>
|
|
|
</van-cell-group>
|
|
</van-cell-group>
|
|
@@ -114,7 +118,8 @@ import { androidFocus, getHeader, goBack, playVoiceBin, scanError, scanSuccess }
|
|
|
import InputBarcode from '@/views/outbound/picking/components/InputBarcode.vue'
|
|
import InputBarcode from '@/views/outbound/picking/components/InputBarcode.vue'
|
|
|
import { closeListener, openListener, scanInit } from '@/utils/keydownListener'
|
|
import { closeListener, openListener, scanInit } from '@/utils/keydownListener'
|
|
|
import { useStore } from '@/store/modules/user'
|
|
import { useStore } from '@/store/modules/user'
|
|
|
-import { getRecommendedLocation } from '@/api/haikang'
|
|
|
|
|
|
|
+import { getRecommendedLocation, getRecommendedLocationNew } from '@/api/haikang'
|
|
|
|
|
+import { findSysParamByKey } from '@/api/basic/index'
|
|
|
import { barcodeToUpperCase } from '@/utils/dataType'
|
|
import { barcodeToUpperCase } from '@/utils/dataType'
|
|
|
import { closeLoading, showLoading } from '@/utils/loading'
|
|
import { closeLoading, showLoading } from '@/utils/loading'
|
|
|
import { getWaitPutawayListNew } from '@/api/putaway'
|
|
import { getWaitPutawayListNew } from '@/api/putaway'
|
|
@@ -124,10 +129,21 @@ try {
|
|
|
androidFocus()
|
|
androidFocus()
|
|
|
} catch (error) {
|
|
} catch (error) {
|
|
|
}
|
|
}
|
|
|
|
|
+// 系统参数:是否开启强制上架(开=getRecommendedLocationNew,关=getRecommendedLocation)
|
|
|
|
|
+const systemForcePublishEnabled = ref(false)
|
|
|
|
|
+async function loadForcePublishParam() {
|
|
|
|
|
+ try {
|
|
|
|
|
+ const res = await findSysParamByKey({ paramKey: 'FORCE_PUBLISH_ENABLED' })
|
|
|
|
|
+ systemForcePublishEnabled.value = res?.data === 'true'
|
|
|
|
|
+ } catch (e) {
|
|
|
|
|
+ console.error(e)
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
// 页面初始化
|
|
// 页面初始化
|
|
|
-onMounted(() => {
|
|
|
|
|
|
|
+onMounted(async () => {
|
|
|
openListener()
|
|
openListener()
|
|
|
scanInit(_handlerScan)
|
|
scanInit(_handlerScan)
|
|
|
|
|
+ await loadForcePublishParam()
|
|
|
loadData()
|
|
loadData()
|
|
|
})
|
|
})
|
|
|
const store = useStore()
|
|
const store = useStore()
|
|
@@ -150,16 +166,20 @@ const inputBarcodeType = ref('barcode')
|
|
|
const location=ref('')
|
|
const location=ref('')
|
|
|
//库位类型
|
|
//库位类型
|
|
|
const locationType = {
|
|
const locationType = {
|
|
|
- 'EA': '件拣货库位',
|
|
|
|
|
- 'AP': '补充拣货位',
|
|
|
|
|
- 'CS': '箱拣货库位',
|
|
|
|
|
- 'HP': '快拣补货位',
|
|
|
|
|
- 'PC': '箱/件合并拣货库位',
|
|
|
|
|
- 'PT': '播种库位',
|
|
|
|
|
- 'RS': '存储库位',
|
|
|
|
|
- 'SS': '理货站',
|
|
|
|
|
- 'ST': '过渡库位',
|
|
|
|
|
- 'WB': '组装工作区',
|
|
|
|
|
|
|
+ "GY": '挂装区',
|
|
|
|
|
+ "TH": '退货拣货位',
|
|
|
|
|
+ "EA": '件拣货库位',
|
|
|
|
|
+ "AP": '补充拣货位',
|
|
|
|
|
+ "CS": '箱拣货库位',
|
|
|
|
|
+ "HP": '快拣补货位',
|
|
|
|
|
+ "PC": '箱/件合并拣货库位',
|
|
|
|
|
+ "PT": '播种库位',
|
|
|
|
|
+ "RS": '存储库位',
|
|
|
|
|
+ "SS": '理货站',
|
|
|
|
|
+ "ST": '过渡库位',
|
|
|
|
|
+ "WB": '组装工作区',
|
|
|
|
|
+ "ZZ": '周转区',
|
|
|
|
|
+ "DZ": '叠装区',
|
|
|
}
|
|
}
|
|
|
// 格口管理相关变量
|
|
// 格口管理相关变量
|
|
|
const bin = ref('') //当前分配的格口号
|
|
const bin = ref('') //当前分配的格口号
|
|
@@ -209,7 +229,23 @@ const _setContainerNo = () => {
|
|
|
//批次数据
|
|
//批次数据
|
|
|
const lotBarcodeList = ref([])
|
|
const lotBarcodeList = ref([])
|
|
|
const lotBarcodeTrueFalseBy = ref(false)
|
|
const lotBarcodeTrueFalseBy = ref(false)
|
|
|
-const barcodeActive = ref({})
|
|
|
|
|
|
|
+const barcodeActiveList = ref([])
|
|
|
|
|
+
|
|
|
|
|
+const _activateSingleBatch = (batchItem) => {
|
|
|
|
|
+ barcodeActiveList.value = batchItem
|
|
|
|
|
+ _getRecommendedLocation(batchItem[0])
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+const _openMultiBatchPicker = () => {
|
|
|
|
|
+ locationList.value = []
|
|
|
|
|
+ barcodeActiveList.value = []
|
|
|
|
|
+ lotBarcodeTrueFalseBy.value = true
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+const onDetailActive = (item) => {
|
|
|
|
|
+ lotBarcodeTrueFalseBy.value = false
|
|
|
|
|
+ _activateSingleBatch(item)
|
|
|
|
|
+}
|
|
|
// 扫描条码监听
|
|
// 扫描条码监听
|
|
|
const _handlerScan = (code) => {
|
|
const _handlerScan = (code) => {
|
|
|
if (code) {
|
|
if (code) {
|
|
@@ -226,17 +262,15 @@ const _handlerScan = (code) => {
|
|
|
}
|
|
}
|
|
|
scanSuccess()
|
|
scanSuccess()
|
|
|
searchBarcode.value = code
|
|
searchBarcode.value = code
|
|
|
- barcodeActive.value = {}
|
|
|
|
|
|
|
+ barcodeActiveList.value = []
|
|
|
lotBarcodeList.value = matchingBarcodeItem(dataMap.value, code)
|
|
lotBarcodeList.value = matchingBarcodeItem(dataMap.value, code)
|
|
|
locationActive.value = []
|
|
locationActive.value = []
|
|
|
bin.value = ''
|
|
bin.value = ''
|
|
|
if (lotBarcodeList.value.length > 0) {
|
|
if (lotBarcodeList.value.length > 0) {
|
|
|
- if (lotBarcodeList.value.length == 1) {
|
|
|
|
|
- barcodeActive.value = lotBarcodeList.value[0]
|
|
|
|
|
- _getRecommendedLocation(lotBarcodeList.value[0].lotNumber, lotBarcodeList.value[0].owner)
|
|
|
|
|
- } else if (lotBarcodeList.value.length > 1) {
|
|
|
|
|
- locationList.value = []
|
|
|
|
|
- lotBarcodeTrueFalseBy.value = true
|
|
|
|
|
|
|
+ if (lotBarcodeList.value.length === 1) {
|
|
|
|
|
+ _activateSingleBatch(lotBarcodeList.value[0])
|
|
|
|
|
+ } else {
|
|
|
|
|
+ _openMultiBatchPicker()
|
|
|
}
|
|
}
|
|
|
} else {
|
|
} else {
|
|
|
scanError()
|
|
scanError()
|
|
@@ -257,7 +291,7 @@ const _handlerScan = (code) => {
|
|
|
const matchingBarcodeItem = (data, barcode) => {
|
|
const matchingBarcodeItem = (data, barcode) => {
|
|
|
const matchingItems = []
|
|
const matchingItems = []
|
|
|
for (const key in data) {
|
|
for (const key in data) {
|
|
|
- const barcodeList = key.match(/\((.*?)\)/)[1].split('、')
|
|
|
|
|
|
|
+ const barcodeList = key.match(/\{(.*?)\}/)[1].split('、')
|
|
|
if (data.hasOwnProperty(key)) {
|
|
if (data.hasOwnProperty(key)) {
|
|
|
if (barcodeList.some(item => barcodeToUpperCase(item) === barcodeToUpperCase(barcode))) {
|
|
if (barcodeList.some(item => barcodeToUpperCase(item) === barcodeToUpperCase(barcode))) {
|
|
|
matchingItems.push(data[key])
|
|
matchingItems.push(data[key])
|
|
@@ -266,33 +300,76 @@ const matchingBarcodeItem = (data, barcode) => {
|
|
|
}
|
|
}
|
|
|
return matchingItems.length > 0 ? matchingItems : []
|
|
return matchingItems.length > 0 ? matchingItems : []
|
|
|
}
|
|
}
|
|
|
-// 获取库存数据
|
|
|
|
|
-const _getRecommendedLocation = async (lotNum, owner) => {
|
|
|
|
|
- try {
|
|
|
|
|
- const params = { warehouse, lotNum, owner,zoneGroup:'WH01-02' }
|
|
|
|
|
- const res = await getRecommendedLocation(params)
|
|
|
|
|
- locationList.value = res.data
|
|
|
|
|
- // 件/箱等拣货库位类型
|
|
|
|
|
- const allowedLocationTypes = ['EA', 'PC', 'GY', 'TH', 'CS']
|
|
|
|
|
- const eaItems = res.data.filter(item => allowedLocationTypes.includes(item.type))
|
|
|
|
|
- // 获取 quantity < 300 的
|
|
|
|
|
- let result = eaItems.find(item => item.quantity !== null && item.quantity < 1000)
|
|
|
|
|
- // 获取 quantity 为 null 的
|
|
|
|
|
- if (!result) {
|
|
|
|
|
- result = eaItems.find(item => item.quantity === null)
|
|
|
|
|
- }
|
|
|
|
|
- if (result) {
|
|
|
|
|
- if(result.quantity===null){
|
|
|
|
|
- scanError()
|
|
|
|
|
- tips.value = `${searchBarcode.value}:库区内无商品库存,请调空料箱进行入库`
|
|
|
|
|
- showNotify({ type: 'danger', duration: 3000, message: `${searchBarcode.value}:库区内无商品库存,请调空料箱进行入库` })
|
|
|
|
|
- searchBarcode.value = ''
|
|
|
|
|
- scanType.value=2
|
|
|
|
|
- return
|
|
|
|
|
|
|
+//待上架数
|
|
|
|
|
+const barcodeQuantity = (list) => {
|
|
|
|
|
+ return list.reduce((sum, item) => sum + Number(item.quantity), 0)
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+// 新旧接口字段映射:旧 location/type/quantity,新 locationId/locationUsage/qty
|
|
|
|
|
+const toLocationItem = (item) => ({
|
|
|
|
|
+ ...item,
|
|
|
|
|
+ location: item.locationId || item.location,
|
|
|
|
|
+ type: item.locationUsage || item.type,
|
|
|
|
|
+ quantity: item.qty ?? item.quantity ?? 0,
|
|
|
|
|
+})
|
|
|
|
|
+
|
|
|
|
|
+// 优先取所有 FORCE 库位,无 FORCE 则取第一个
|
|
|
|
|
+const pickRecommendedLocations = (loc) => {
|
|
|
|
|
+ const forceLocs = loc.filter(item => item.displayType === 'FORCE')
|
|
|
|
|
+ const source = forceLocs.length > 0 ? forceLocs : [loc[0]]
|
|
|
|
|
+ return source.map(toLocationItem)
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+// 获取推荐库位(根据 systemForcePublishEnabled 分流新旧接口)
|
|
|
|
|
+const _getRecommendedLocation = async (item) => {
|
|
|
|
|
+ const { lotNumber, owner, sku, lotAtt08 } = item
|
|
|
|
|
+ if (!systemForcePublishEnabled.value) {
|
|
|
|
|
+ try {
|
|
|
|
|
+ const params = { warehouse, lotNum: lotNumber, owner, zoneGroup: 'WH01-02' }
|
|
|
|
|
+ const res = await getRecommendedLocation(params)
|
|
|
|
|
+ locationList.value = res.data || []
|
|
|
|
|
+ const allowedLocationTypes = ['EA', 'PC', 'GY', 'TH', 'CS']
|
|
|
|
|
+ const eaItems = locationList.value.filter(loc => allowedLocationTypes.includes(loc.type))
|
|
|
|
|
+ let result = eaItems.find(loc => loc.quantity !== null && loc.quantity < 1000)
|
|
|
|
|
+ if (!result) {
|
|
|
|
|
+ result = eaItems.find(loc => loc.quantity === null)
|
|
|
}
|
|
}
|
|
|
- setLocation([result])
|
|
|
|
|
|
|
+ if (result) {
|
|
|
|
|
+ if (result.quantity === null) {
|
|
|
|
|
+ scanError()
|
|
|
|
|
+ const msg = `${searchBarcode.value}:库区内无商品库存,请调空料箱进行入库`
|
|
|
|
|
+ tips.value = msg
|
|
|
|
|
+ showNotify({ type: 'danger', duration: 3000, message: msg })
|
|
|
|
|
+ searchBarcode.value = ''
|
|
|
|
|
+ scanType.value = 2
|
|
|
|
|
+ return
|
|
|
|
|
+ }
|
|
|
|
|
+ setLocation([result])
|
|
|
|
|
+ }
|
|
|
|
|
+ } catch (err) {
|
|
|
|
|
+ console.error(err)
|
|
|
}
|
|
}
|
|
|
|
|
+ return
|
|
|
|
|
+ }
|
|
|
|
|
+ try {
|
|
|
|
|
+ const total = barcodeQuantity(barcodeActiveList.value)
|
|
|
|
|
+ const params = { warehouse, lotNum: lotNumber, owner, sku, qty: total, lotAtt08, zoneId: 'WH01-02' }
|
|
|
|
|
+ const res = await getRecommendedLocationNew(params)
|
|
|
|
|
+ const loc = res.data?.locationList || []
|
|
|
|
|
+ locationList.value = loc
|
|
|
|
|
+ if (loc.length === 0) {
|
|
|
|
|
+ scanError()
|
|
|
|
|
+ const msg = `${searchBarcode.value}:库区内无商品库存,请调空料箱进行入库`
|
|
|
|
|
+ tips.value = msg
|
|
|
|
|
+ showNotify({ type: 'danger', duration: 3000, message: msg })
|
|
|
|
|
+ searchBarcode.value = ''
|
|
|
|
|
+ scanType.value = 2
|
|
|
|
|
+ return
|
|
|
|
|
+ }
|
|
|
|
|
+ setLocation(pickRecommendedLocations(loc))
|
|
|
} catch (err) {
|
|
} catch (err) {
|
|
|
|
|
+ locationList.value = []
|
|
|
|
|
+ scanError()
|
|
|
console.error(err)
|
|
console.error(err)
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
@@ -379,17 +456,17 @@ const resetScanState = () => {
|
|
|
searchBarcode.value = ''
|
|
searchBarcode.value = ''
|
|
|
locationActive.value = []
|
|
locationActive.value = []
|
|
|
bin.value = ''
|
|
bin.value = ''
|
|
|
- barcodeActive.value = ''
|
|
|
|
|
|
|
+ barcodeActiveList.value = []
|
|
|
scanType.value = 3
|
|
scanType.value = 3
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
// 设置库位
|
|
// 设置库位
|
|
|
-const setLocation = (item) => {
|
|
|
|
|
- locationActive.value = item
|
|
|
|
|
|
|
+const setLocation = (items) => {
|
|
|
|
|
+ locationActive.value = items.map(toLocationItem)
|
|
|
const storedData = getBinStorageData()
|
|
const storedData = getBinStorageData()
|
|
|
const container = containerNo.value
|
|
const container = containerNo.value
|
|
|
const wall = wallNo.value
|
|
const wall = wallNo.value
|
|
|
- const lotNumber = barcodeActive.value.lotNumber
|
|
|
|
|
|
|
+ const lotNumber = barcodeActiveList.value[0].lotNumber
|
|
|
// 初始化数据结构
|
|
// 初始化数据结构
|
|
|
initializeBinData(storedData, container, wall)
|
|
initializeBinData(storedData, container, wall)
|
|
|
// 分配格口号
|
|
// 分配格口号
|
|
@@ -419,10 +496,10 @@ const setLocation = (item) => {
|
|
|
warehouse,
|
|
warehouse,
|
|
|
equipment: wallNo.value,
|
|
equipment: wallNo.value,
|
|
|
container: containerNo.value,
|
|
container: containerNo.value,
|
|
|
- barcode: barcodeActive.value.barcode,
|
|
|
|
|
|
|
+ barcode: barcodeActiveList.value[0].barcode,
|
|
|
bin: bin.value,
|
|
bin: bin.value,
|
|
|
- location: [locationActive.value[0].location],
|
|
|
|
|
- lotNum: barcodeActive.value.lotNumber,
|
|
|
|
|
|
|
+ location: locationActive.value.map(item => item.location),
|
|
|
|
|
+ lotNum: barcodeActiveList.value[0].lotNumber,
|
|
|
sysVersion: 'V6'
|
|
sysVersion: 'V6'
|
|
|
}
|
|
}
|
|
|
// 提交格口绑定数据,请求成功后再缓存数据
|
|
// 提交格口绑定数据,请求成功后再缓存数据
|
|
@@ -537,11 +614,11 @@ const loadData = () => {
|
|
|
//根据条码批次分组数据
|
|
//根据条码批次分组数据
|
|
|
const groupedData = (data) => {
|
|
const groupedData = (data) => {
|
|
|
return data.reduce((acc, item) => {
|
|
return data.reduce((acc, item) => {
|
|
|
- const key = `(${item.barcode}、${item.barcodeAs}、${item.sku})-${item.lotNumber}`
|
|
|
|
|
|
|
+ const key = `{${item.barcode}、${item.barcodeAs}、${item.sku}}-${item.lotNumber}`
|
|
|
if (acc[key]) {
|
|
if (acc[key]) {
|
|
|
- acc[key].quantity += item.quantity
|
|
|
|
|
|
|
+ acc[key].push(item)
|
|
|
} else {
|
|
} else {
|
|
|
- acc[key] = { ...item }
|
|
|
|
|
|
|
+ acc[key] = [item]
|
|
|
}
|
|
}
|
|
|
return acc
|
|
return acc
|
|
|
}, {})
|
|
}, {})
|
|
@@ -699,6 +776,15 @@ window.onRefresh = loadData
|
|
|
.task-table-bin tbody
|
|
.task-table-bin tbody
|
|
|
background: #cde7ff
|
|
background: #cde7ff
|
|
|
|
|
|
|
|
|
|
+ .display-type--force
|
|
|
|
|
+ background-color: #81c784
|
|
|
|
|
+
|
|
|
|
|
+ .display-type--optional
|
|
|
|
|
+ background-color: #fff
|
|
|
|
|
+
|
|
|
|
|
+ .display-type--inventory
|
|
|
|
|
+ background-color: #d8d8d8
|
|
|
|
|
+
|
|
|
.nav-right
|
|
.nav-right
|
|
|
padding: 14px 0 12px 5px
|
|
padding: 14px 0 12px 5px
|
|
|
color: #fff
|
|
color: #fff
|