Explorar el Código

宝时快上-增加默认退货容器退货区域

zhaohuanhuan hace 2 semanas
padre
commit
63a91394de
Se han modificado 1 ficheros con 165 adiciones y 13 borrados
  1. 165 13
      src/views/inbound/putaway/task/index.vue

+ 165 - 13
src/views/inbound/putaway/task/index.vue

@@ -73,6 +73,18 @@
             @focus="scanType=3"
             autocomplete="off"
           >
+            <template #right-icon>
+              <van-button
+                v-if="barcodeActiveList.length > 0"
+                type="primary"
+                size="mini"
+                plain
+                :loading="changeLocationLoading"
+                @click.stop="onChangeLocation"
+              >
+                换一换
+              </van-button>
+            </template>
           </van-search>
         </div>
         <div class="barcode-input">
@@ -100,6 +112,9 @@
             </template>
           </van-search>
         </div>
+        <div class="barcode-input location-type-row">
+          <van-cell title="上架区域:" :value="locationTypeLabel"  is-link @click="locationTypeSheetShow = true" />
+        </div>
       </div>
       <div class="take-lot" v-if="barcodeActiveList.length>0">
         <van-cell-group>
@@ -141,6 +156,17 @@
       </van-cell>
     </van-cell-group>
   </van-action-sheet>
+  <!--  库位类型选择-->
+  <van-action-sheet v-model:show="locationTypeSheetShow" cancel-text="取消" description="上架区域"
+                    close-on-click-action>
+    <van-cell-group>
+      <van-cell title="全部" @click="onSelectLocationType()" />
+      <van-cell title="拣货区" @click="onSelectLocationType('PICKING')" />
+      <van-cell title="存储区" @click="onSelectLocationType('STORAGE')" />
+      <van-cell title="退货区" @click="onSelectLocationType('RETURN')" />
+      <van-cell title="挂装区" @click="onSelectLocationType('HANGING')" />
+    </van-cell-group>
+  </van-action-sheet>
   <!--  推荐库位列表-->
   <van-action-sheet v-model:show="locationTrueFalseBy" cancel-text="取消" description="推荐库位列表"
                     close-on-click-action>
@@ -167,7 +193,7 @@ import { getCurrentTime } from '@/utils/date'
 import { getWaitPutawayListNew, setPutawayNew } from '@/api/putaway/index'
 import { getListCombineSku } from '@/api/picking'
 import { barcodeToUpperCase } from '@/utils/dataType.js'
-import { getRecommendedLocation } from '@/api/haikang/index'
+import { getRecommendedLocationNew } from '@/api/haikang/index'
 import { getOwnerList } from '@/hooks/basic/index'
 
 const router = useRouter()
@@ -178,8 +204,10 @@ try {
 } catch (error) {
   router.push('/login')
 }
+/** 精准推荐是否开启 */
+const forcePublishEnabled = ref(true)
 // 页面初始化
-onMounted(() => {
+onMounted(async () => {
   openListener()
   scanInit(_handlerScan)
   loadData()
@@ -268,6 +296,7 @@ const setBarcode = (code, type) => {
     stopTimer()
     formattedTime.value = '00:00:00'
     totalSeconds.value = 0
+    locationType.value = ''
   }
   const params = { warehouseId:warehouse, containerId: code }
   getWaitPutawayListNew(params).then(res => {
@@ -325,6 +354,9 @@ const setBarcode = (code, type) => {
       dataList.value = [...asnToShelfList,...noAsnToShelfList]
       dataMap.value = groupedData(dataList.value)
       containerNo.value = code
+      if (!type && code?.includes('TH-')) {
+        locationType.value = 'RETURN'
+      }
       scanSuccess()
     } else {
       reset()
@@ -373,6 +405,8 @@ const matchingBarcodeItem = (data, barcode) => {
 const switchTask = () => {
   inputBarcodeType.value = 'switchTask'
   back.value = false
+  excludedLocations.value = {}
+  locationType.value = ''
   inputBarcodeRef.value?.show('', `请扫描容器号`, '')
 }
 
@@ -384,6 +418,26 @@ const barcodeActiveList = ref([])
 const barcodeCombineRef = ref(null)
 const putawayCombineData = ref(null)
 const combineMatchedSku = ref([])
+// 已推荐过的库位,按 lotNum 批次维度存储,用于换一换时排除
+const excludedLocations = ref({})
+// 换一换按钮 loading
+const changeLocationLoading = ref(false)
+// 库位类型,默认全部
+const locationType = ref('')
+const locationTypeSheetShow = ref(false)
+const locationTypeLabel = computed(() => {
+  const map = { PICKING: '拣货位', STORAGE: '存储位', RETURN: '退货区', HANGING: '挂装区' }
+  return locationType.value ? map[locationType.value] : '全部'
+})
+const onSelectLocationType = async (value = '') => {
+  const prev = locationType.value
+  locationType.value = value
+  locationTypeSheetShow.value = false
+  if (value !== prev && barcodeActiveList.value.length > 0) {
+    excludedLocations.value = {}
+    await _getRecommendedLocation(barcodeActiveList.value[0])
+  }
+}
 const reset = () => {
   searchCount.value = ''
   searchBarcode.value = ''
@@ -393,6 +447,7 @@ const reset = () => {
   barcodeActiveList.value = []
   putawayCombineData.value = null
   combineMatchedSku.value = []
+  excludedLocations.value = {}
 }
 // 组合商品上架数量弹框
 const _showPutawayCombineDialog = (batchItem) => {
@@ -424,13 +479,13 @@ const onDetailActive = (item) => {
   lotBarcodeTrueFalseBy.value = false
   if (putawayCombineData.value) {
     _showPutawayCombineDialog(item)
-    _getRecommendedLocation(item[0].lotNumber, item[0].owner)
+    _getRecommendedLocation(item[0])
     scanType.value = 3
     return
   }
   searchCount.value = 1
   scanType.value = 3
-  _getRecommendedLocation(item[0].lotNumber, item[0].owner)
+  _getRecommendedLocation(item[0])
   scanSuccess()
 }
 const onAsnCancel = () => {
@@ -462,7 +517,7 @@ const _handlePutawayCombineProduct = (code) => {
       if (lotBarcodeList.value.length === 1) {
         barcodeActiveList.value = lotBarcodeList.value[0]
         _showPutawayCombineDialog(lotBarcodeList.value[0])
-        _getRecommendedLocation(barcodeActiveList.value[0].lotNumber, barcodeActiveList.value[0].owner)
+        _getRecommendedLocation(barcodeActiveList.value[0])
         scanType.value = 3
       } else {
         locationList.value = []
@@ -491,7 +546,7 @@ const _handlerScan = (code) => {
       combineMatchedSku.value = []
       if (lotBarcodeList.value.length == 1) {
         barcodeActiveList.value = lotBarcodeList.value[0]
-        _getRecommendedLocation(barcodeActiveList.value[0].lotNumber, barcodeActiveList.value[0].owner)
+        _getRecommendedLocation(barcodeActiveList.value[0])
         scanType.value = 3
         scanSuccess()
       } else if (lotBarcodeList.value.length > 1) {
@@ -505,22 +560,81 @@ const _handlerScan = (code) => {
       _handlePutawayCombineProduct(code)
     }
   } else if (scanType.value == 3) {
-    searchLocation.value = barcodeToUpperCase(code)
+    const scannedLocation = barcodeToUpperCase(code)
+    if (!forcePublishEnabled.value) {
+      const { lotAtt02 } = barcodeActiveList.value[0]
+      if (locationList.value.length > 0 && !lotAtt02) {
+        const recommendedLocations = locationList.value.map(item => barcodeToUpperCase(item.locationId || ''))
+        if (!recommendedLocations.includes(scannedLocation)) {
+          showNotify({ type: 'warning', duration: 3000, message: `扫描库位${scannedLocation}与推荐库位不一致,请确认` })
+          searchLocation.value=''
+          scanError()
+          return
+        }
+      }
+    }
+    searchLocation.value = scannedLocation
     scanType.value = 4
     if (!searchCount.value) searchCount.value = 1
     scanSuccess()
   }
 }
-// 获取库存数据
-const _getRecommendedLocation = async (lotNum, owner) => {
+// 获取推荐库位
+const _getRecommendedLocation = async (item, options = {}) => {
+  const { fromChangeLocation = false } = options
+  const { lotNumber, owner } = item
+  const { sku, quantity, lotAtt08 } = item
+  const listByLot = fromChangeLocation ? (excludedLocations.value[lotNumber] || []) : []
+  const uniqueLocationIds = listByLot.length > 0
+    ? [...new Set(listByLot.map(loc => loc.locationId).filter(Boolean))]
+    : undefined
   try {
-    const params = { warehouse, lotNum, owner }
-    const res = await getRecommendedLocation(params)
-    locationList.value = res.data
+    const total = barcodeQuantity(barcodeActiveList.value)
+    const params = { warehouse, lotNum: lotNumber, owner, sku, qty: total, lotAtt08 }
+    if (locationType.value) params.locationUse = locationType.value
+    if (fromChangeLocation && uniqueLocationIds) params.excludedLocations = uniqueLocationIds
+    const res = await getRecommendedLocationNew(params)
+    if (res.data) {
+      forcePublishEnabled.value = res.data.forbidForcePutaway
+      const loc = res.data.locationList
+      if (fromChangeLocation) {
+        // 按批次维度存储已推荐库位(与接口 locationList 项一致,含 locationId),用于后续换一换排除
+        const lotExcluded = excludedLocations.value[lotNumber] || []
+        const recommended = Array.isArray(loc) ? loc : []
+        excludedLocations.value = {
+          ...excludedLocations.value,
+          [lotNumber]: [...lotExcluded, ...recommended]
+        }
+      }
+      locationList.value = loc
+      searchCount.value = 1
+    }
   } catch (err) {
     console.error(err)
   }
 }
+
+// 换一换:请求新的推荐库位,排除当前批次已推荐过的
+const onChangeLocation = async () => {
+  if (barcodeActiveList.value.length > 0) {
+    changeLocationLoading.value = true
+    try {
+      const item = barcodeActiveList.value[0]
+      const lotNumber = item.lotNumber
+      const currentLoc = locationList.value?.[0]?.location ?? locationList.value?.[0]
+      if (currentLoc) {
+        const lotExcluded = excludedLocations.value[lotNumber] || []
+        excludedLocations.value = {
+          ...excludedLocations.value,
+          [lotNumber]: [...lotExcluded, currentLoc]
+        }
+      }
+      await _getRecommendedLocation(item, { fromChangeLocation: true })
+    } finally {
+      changeLocationLoading.value = false
+    }
+  }
+}
 const numberRef = ref(null)
 const locationRef = ref(null)
 // 完成收货校验
@@ -531,6 +645,23 @@ const isCheck = () => {
     showToast({ duration: 3000, message: '请先扫描库位编号' })
     return false
   }
+  if (!forcePublishEnabled.value) {
+    if(barcodeActiveList.value.length ==0) {
+      showToast({ duration: 3000, message: '数据异常请重新扫描' })
+      scanError()
+      return
+    }
+    const { lotAtt02 } = barcodeActiveList.value[0]
+    if (locationList.value.length > 0 && !lotAtt02) {
+      const recommendedLocations = locationList.value.map(item => barcodeToUpperCase(item.locationId || ''))
+      if (!recommendedLocations.includes(barcodeToUpperCase(searchLocation.value))) {
+        locationRef.value?.focus()
+        scanError()
+        showToast({ duration: 3000, message: '库位与推荐库位不一致,无法上架' })
+        return false
+      }
+    }
+  }
   if (searchCount.value == '') {
     numberRef.value?.focus()
     scanError()
@@ -717,9 +848,30 @@ window.onRefresh = loadData
         font-size: 16px
         font-weight: bold
 
-      ::v-deep(.van-search__label)
+      ::v-deep(.van-search__label),
+      ::v-deep(.van-field__label)
+        width: 6.5em
+        min-width: 6.5em
+        max-width: 6.5em
+        flex: none
         font-size: 16px
         font-weight: bold
+        margin-right: 0
+        text-align: left
+
+      &.location-type-row
+        ::v-deep(.van-cell__title)
+          width: 6.5em
+          min-width: 6.5em
+          max-width: 6.5em
+          flex: none
+          font-size: 16px
+          font-weight: bold
+
+        ::v-deep(.van-cell__value)
+          font-size: 14px
+          font-weight: bold
+          color: #323233
 
       .search-input-barcode
         ::v-deep(.van-search__field)