zh 3 месяцев назад
Родитель
Сommit
5bae08ab9e
2 измененных файлов с 129 добавлено и 14 удалено
  1. 26 0
      src/api/location/merge.ts
  2. 103 14
      src/views/robot/merge/index.vue

+ 26 - 0
src/api/location/merge.ts

@@ -83,3 +83,29 @@ export function reissueTask(warehouse: string, stationCode: string, boxCode: str
     params: { warehouse, stationCode, boxCode }
   })
 }
+
+/**
+ * 获取料箱状态映射
+ * @param warehouse 仓库
+ * @param boxCodeList 料箱编码列表
+ */
+export function getBoxStatus(warehouse: string, boxCodeList: string[]) {
+  return request<Record<string, number>>({
+    url: '/api/wms/location/merge/boxStatus',
+    method: 'get',
+    params: { warehouse, boxCodeList },
+    paramsSerializer: (params: any) => {
+      const searchParams = new URLSearchParams()
+      Object.keys(params).forEach(key => {
+        const value = params[key]
+        if (Array.isArray(value)) {
+          // Spring @RequestParam List 期望格式: key=v1&key=v2
+          value.forEach(item => searchParams.append(key, item))
+        } else {
+          searchParams.append(key, value)
+        }
+      })
+      return searchParams.toString()
+    }
+  })
+}

+ 103 - 14
src/views/robot/merge/index.vue

@@ -109,12 +109,12 @@
               'box-waiting': station.status === 'waiting',
               'box-error': station.status === 'error',
               'box-selected': selectedBox === station.stationCode,
-              'box-split': station.splitCount
+              'box-split': station.splitCount && station.status !== 'error' && station.status !== 'waiting'
             }"
                         @click="handleStationClick(station)"
           >
-            <!-- 分割的料箱 -->
-            <template v-if="station.splitCount && station.subLocations">
+                      <!-- 分割的料箱(异常/等待调箱状态不渲染分割) -->
+            <template v-if="station.splitCount && station.subLocations && station.status !== 'error' && station.status !== 'waiting'">
               <div class="sub-grid" :style="getSubGridStyle(station.splitCount)">
                 <div
                   v-for="sub in station.subLocations"
@@ -129,7 +129,7 @@
                 ></div>
               </div>
             </template>
-            <!-- 普通站台 -->
+            <!-- 普通站台或异常状态 -->
             <template v-else>
               <span v-if="station.label" class="box-label">{{ station.label }}</span>
             </template>
@@ -199,7 +199,7 @@ import { closeListener, openListener, scanInit } from '@/utils/keydownListener'
 import { onMounted, onUnmounted, ref, reactive, nextTick } from 'vue'
 import { showToast, showLoadingToast, closeToast } from 'vant'
 import { useStore } from '@/store/modules/user'
-import { getWorkingDetailsByBox, getBoxSplitCode, boxInbound, reissueTask, type BoxRelatedMergeDetailsVO, type LocationMergeDetails } from '@/api/location/merge'
+import { getWorkingDetailsByBox, getBoxSplitCode, boxInbound, reissueTask, getBoxStatus, type BoxRelatedMergeDetailsVO, type LocationMergeDetails } from '@/api/location/merge'
 import { getInventory, inventoryMovement } from '@/api/inventory'
 import { showConfirmDialog } from 'vant'
 
@@ -222,6 +222,9 @@ const sourceLocation = ref('')
 // 商品条码
 const scanBarcode = ref('')
 
+// 轮询定时器
+let pollingTimer: ReturnType<typeof setInterval> | null = null
+
 // 页面初始化
 onMounted(() => {
   openListener()
@@ -234,6 +237,7 @@ onMounted(() => {
 
 onUnmounted(() => {
   closeListener()
+  stopPolling()
 })
 
 // 设置料箱号输入框焦点
@@ -472,6 +476,11 @@ const loadBoxData = async (code: string) => {
 
     closeToast()
     
+    // 加载完成后检查是否需要启动轮询
+    if (hasWaitingBox()) {
+      startPolling()
+    }
+    
     // 加载完成后focus到源库位输入框
     scanType.value = 2
     focusSourceLocationInput()
@@ -734,8 +743,6 @@ const currentLocation = reactive({
 
 // 点击站台处理
 const handleStationClick = (station: StationItem) => {
-  // 分割的料箱不处理,由子库位处理
-  if (station.splitCount) return
   // 离线状态不可点击
   if (station.status === 'offline') return
   // 异常状态弹出重新下发确认框
@@ -743,6 +750,8 @@ const handleStationClick = (station: StationItem) => {
     showReissueConfirm(station)
     return
   }
+  // 分割的料箱不处理,由子库位处理
+  if (station.splitCount) return
   // 其他状态正常选择
   selectStation(station)
 }
@@ -761,6 +770,86 @@ const showReissueConfirm = (station: StationItem) => {
     })
 }
 
+// 获取当前所有料箱编码列表
+const getBoxCodeList = (): string[] => {
+  return stationList.value
+    .filter(s => s.boxCode && s.status !== 'offline')
+    .map(s => s.boxCode!)
+}
+
+// 检查是否存在等待调箱的料箱
+const hasWaitingBox = (): boolean => {
+  return stationList.value.some(s => s.status === 'waiting')
+}
+
+// 局部更新料箱状态
+const refreshBoxStatus = async () => {
+  const boxCodeList = getBoxCodeList()
+  if (boxCodeList.length === 0) return
+
+  try {
+    const res = await getBoxStatus(warehouse, boxCodeList)
+    const statusMap = res.data || {}
+    
+    // 更新站台列表中的状态
+    stationList.value = stationList.value.map(station => {
+      if (!station.boxCode || !statusMap.hasOwnProperty(station.boxCode)) {
+        return station
+      }
+      
+      const newBoxStatus = statusMap[station.boxCode]
+      const inventoryLocations = station.inventoryLocations || []
+      
+      let status: StationItem['status'] = 'offline'
+      let label: string | undefined = undefined
+      
+      if (newBoxStatus === 0 || newBoxStatus === 10) {
+        status = 'waiting'
+        label = '等待调箱'
+      } else if (newBoxStatus === 20) {
+        if (inventoryLocations.length === 0) {
+          status = 'emptyBox'
+          label = '空箱'
+        } else {
+          status = 'filled'
+        }
+      } else if (newBoxStatus === 30) {
+        status = 'offline'
+      } else if (newBoxStatus === 40) {
+        status = 'error'
+        label = '异'
+      }
+      
+      return { ...station, status, label }
+    })
+    
+    // 检查是否需要继续轮询
+    if (hasWaitingBox()) {
+      startPolling()
+    } else {
+      stopPolling()
+    }
+  } catch (error) {
+    console.error('刷新料箱状态失败', error)
+  }
+}
+
+// 启动轮询
+const startPolling = () => {
+  if (pollingTimer) return // 已经在轮询中
+  pollingTimer = setInterval(() => {
+    refreshBoxStatus()
+  }, 10000) // 10秒
+}
+
+// 停止轮询
+const stopPolling = () => {
+  if (pollingTimer) {
+    clearInterval(pollingTimer)
+    pollingTimer = null
+  }
+}
+
 // 执行重新下发任务
 const doReissueTask = async (station: StationItem) => {
   if (!station.boxCode) {
@@ -772,10 +861,10 @@ const doReissueTask = async (station: StationItem) => {
     await reissueTask(warehouse, station.stationCode, station.boxCode)
     closeToast()
     showToast('重新下发成功')
-    // 重新加载料箱数据
-    if (boxCode.value) {
-      loadBoxData(boxCode.value)
-    }
+    // 局部刷新料箱状态
+    setTimeout(() => {
+      refreshBoxStatus()
+    }, 500)
   } catch (error: any) {
     closeToast()
     showToast(error.message || '重新下发失败')
@@ -1096,13 +1185,13 @@ const submitMove = () => {
       border-color: #e0b0b0;
     }
 
-    &.box-error {
+        &.box-error {
       background: #ffcccc;
       border-color: #ff6666;
+      cursor: pointer;
 
       .box-label {
-        color: #ff0000;
-        font-weight: bold;
+        color: #cc0000;
       }
     }