Przeglądaj źródła

海柔快上-增加精准推荐逻辑

zhaohuanhuan 3 dni temu
rodzic
commit
6638cebc2c
1 zmienionych plików z 150 dodań i 64 usunięć
  1. 150 64
      src/views/robot/putaway/index.vue

+ 150 - 64
src/views/robot/putaway/index.vue

@@ -68,10 +68,15 @@
           </tr>
           </thead>
           <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>
               <!--              <van-button type="primary" plain size="mini" style="width:100%" @click="setLocation(item)" v-if="!locationActive.location">选择</van-button>-->
               <div>
@@ -91,16 +96,15 @@
     <!-- 条码输入组件 -->
     <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>
       <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>
-            {{ item.barcode }}({{ item.quantity }}件)
+            {{ item[0].barcode }}({{ item[0].lotNumber }}-{{ barcodeQuantity(item) }}件)
           </template>
           <template #label>
-            生产日期:{{ item.lotAtt01 || '--' }}-失效日期:{{ item.lotAtt02 || '--' }}
+            生产日期:{{ item[0].lotAtt01 || '--' }}-失效日期:{{ item[0].lotAtt02 || '--' }}
           </template>
         </van-cell>
       </van-cell-group>
@@ -114,7 +118,8 @@ import { androidFocus, getHeader, goBack, playVoiceBin, scanError, scanSuccess }
 import InputBarcode from '@/views/outbound/picking/components/InputBarcode.vue'
 import { closeListener, openListener, scanInit } from '@/utils/keydownListener'
 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 { closeLoading, showLoading } from '@/utils/loading'
 import { getWaitPutawayListNew } from '@/api/putaway'
@@ -124,10 +129,21 @@ try {
   androidFocus()
 } 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()
   scanInit(_handlerScan)
+  await loadForcePublishParam()
   loadData()
 })
 const store = useStore()
@@ -150,16 +166,20 @@ const inputBarcodeType = ref('barcode')
 const location=ref('')
 //库位类型
 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('') //当前分配的格口号
@@ -209,7 +229,23 @@ const _setContainerNo = () => {
 //批次数据
 const lotBarcodeList = ref([])
 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) => {
   if (code) {
@@ -226,17 +262,15 @@ const _handlerScan = (code) => {
       }
       scanSuccess()
       searchBarcode.value = code
-      barcodeActive.value = {}
+      barcodeActiveList.value = []
       lotBarcodeList.value = matchingBarcodeItem(dataMap.value, code)
       locationActive.value = []
       bin.value = ''
       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 {
         scanError()
@@ -257,7 +291,7 @@ const _handlerScan = (code) => {
 const matchingBarcodeItem = (data, barcode) => {
   const matchingItems = []
   for (const key in data) {
-    const barcodeList = key.match(/\((.*?)\)/)[1].split('、')
+    const barcodeList = key.match(/\{(.*?)\}/)[1].split('、')
     if (data.hasOwnProperty(key)) {
       if (barcodeList.some(item => barcodeToUpperCase(item) === barcodeToUpperCase(barcode))) {
         matchingItems.push(data[key])
@@ -266,33 +300,76 @@ const matchingBarcodeItem = (data, barcode) => {
   }
   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) {
+    locationList.value = []
+    scanError()
     console.error(err)
   }
 }
@@ -379,17 +456,17 @@ const resetScanState = () => {
   searchBarcode.value = ''
   locationActive.value = []
   bin.value = ''
-  barcodeActive.value = ''
+  barcodeActiveList.value = []
   scanType.value = 3
 }
 
 // 设置库位
-const setLocation = (item) => {
-  locationActive.value = item
+const setLocation = (items) => {
+  locationActive.value = items.map(toLocationItem)
   const storedData = getBinStorageData()
   const container = containerNo.value
   const wall = wallNo.value
-  const lotNumber = barcodeActive.value.lotNumber
+  const lotNumber = barcodeActiveList.value[0].lotNumber
   // 初始化数据结构
   initializeBinData(storedData, container, wall)
   // 分配格口号
@@ -419,10 +496,10 @@ const setLocation = (item) => {
     warehouse,
     equipment: wallNo.value,
     container: containerNo.value,
-    barcode: barcodeActive.value.barcode,
+    barcode: barcodeActiveList.value[0].barcode,
     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'
   }
   // 提交格口绑定数据,请求成功后再缓存数据
@@ -537,11 +614,11 @@ const loadData = () => {
 //根据条码批次分组数据
 const groupedData = (data) => {
   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]) {
-      acc[key].quantity += item.quantity
+      acc[key].push(item)
     } else {
-      acc[key] = { ...item }
+      acc[key] = [item]
     }
     return acc
   }, {})
@@ -699,6 +776,15 @@ window.onRefresh = loadData
       .task-table-bin tbody
         background: #cde7ff
 
+      .display-type--force
+        background-color: #81c784
+
+      .display-type--optional
+        background-color: #fff
+
+      .display-type--inventory
+        background-color: #d8d8d8
+
   .nav-right
     padding: 14px 0 12px 5px
     color: #fff