zhaohuanhuan 7 месяцев назад
Родитель
Сommit
1f7eb4c427

+ 14 - 0
src/api/takeDelivery/index.ts

@@ -99,4 +99,18 @@ export function setReceiving(data:setReceivingType) {
 }
 
 
+/**
+ * 完成收货
+ * @param params
+ */
+export function setBotReceiving(data:setReceivingType) {
+  return request({
+    url: '/api/wms/receiving/botReceiving',
+    method: 'post',
+    data
+  })
+}
+
+
+
 

+ 53 - 47
src/hooks/basic/menu.js

@@ -1,6 +1,6 @@
 import {
   reactive,
-  ref
+  ref,
 } from 'vue'
 
 export default function() {
@@ -10,116 +10,122 @@ export default function() {
       title: '工作台',
       id: 0,
       icon: 'home-o',
-      menu:[{
-        title:'入库',
-        children: [
-          {
-            title: '收货',
-            icon: 'newspaper-o',
-            path: 'take-delivery'
-          },
-          {
-            title: '盲扫',
-            icon: 'newspaper-o',
-            path: 'blind-receiving'
-          },
-          {
-            title: '宝时快上',
-            icon: 'newspaper-o',
-            path: 'putaway'
-          },
-        ]
-      },
+      menu: [
         {
-          title:'出库',
+          title: '入库',
+          children: [
+            {
+              title: '收货',
+              icon: 'newspaper-o',
+              path: 'take-delivery',
+            },
+            {
+              title: '盲扫',
+              icon: 'newspaper-o',
+              path: 'blind-receiving',
+            },
+            {
+              title: '宝时快上',
+              icon: 'newspaper-o',
+              path: 'putaway',
+            },
+          ],
+        },
+        {
+          title: '出库',
           children: [
             {
               title: '拣货',
               icon: 'newspaper-o',
-              path: 'picking'
+              path: 'picking',
             },
             {
               title: '拣货(巷道)',
               icon: 'newspaper-o',
-              path: 'picking-aisle'
+              path: 'picking-aisle',
             },
             {
               title: '活动单复核',
               icon: 'newspaper-o',
-              path: 'check-activity'
+              path: 'check-activity',
             },
             {
               title: 'B2B复核',
               icon: 'newspaper-o',
-              path: 'check-large'
+              path: 'check-large',
             },
             {
               title: '复核还库',
               icon: 'newspaper-o',
-              path: 'check-move-stock'
+              path: 'check-move-stock',
             },
-          ]
+          ],
         },
         {
-          title:'库存',
+          title: '库存',
           children: [
             {
               title: '移库任务',
               icon: 'newspaper-o',
-              path: 'move-list'
+              path: 'move-list',
             },
-          ]
+          ],
         },
         {
-          title:'海康',
+          title: '机器人',
           children: [
             {
               title: '海康快上',
               icon: 'newspaper-o',
-              path: 'hik-putaway-allocation'
+              path: 'hik-putaway-allocation',
             },
             {
               title: '海康上架',
               icon: 'newspaper-o',
-              path: 'hik-putaway'
+              path: 'hik-putaway',
             },
             {
               title: '海康入库',
               icon: 'newspaper-o',
-              path: 'hik-box-return'
+              path: 'hik-box-return',
+            },
+            {
+              title: '智能仓收货',
+              icon: 'newspaper-o',
+              path: 'robot-take-delivery',
             },
-          ]
+          ],
         },
         {
-          title:'其他',
+          title: '其他',
           children: [
             {
               title: '加工单',
               icon: 'newspaper-o',
-              path: 'processing'
+              path: 'processing',
             },
             {
               title: '计件面板',
               icon: 'newspaper-o',
-              path: 'piece-dashboard'
+              path: 'piece-dashboard',
             },
             {
               title: '退货登记',
               icon: 'newspaper-o',
-              path: 'returned-register'
+              path: 'returned-register',
             },
             {
-              title: '容器操作',
+              title: '容器移动',
               icon: 'newspaper-o',
-              path: 'container-operation'
+              path: 'container-operation',
             },
-          ]
-        },
 
-      ]
+          ],
+        },
+      ],
     },
-  ]);
+  ])
   return {
-    menuList
+    menuList,
   }
 }

+ 7 - 1
src/router/index.ts

@@ -79,6 +79,12 @@ const routes: RouteRecordRaw[] = [
     meta:{title:'海康-入库'},
     component: () => import('@/views/haikang/boxReturn/boxReturn/index.vue')
   },
+  {
+    path: '/robot-take-delivery',
+    name: 'RobotTakeDelivery',
+    meta:{title:'智能仓收货'},
+    component: () => import('@/views/robot/takeDelivery/task/index.vue')
+  },
   {
     path: '/check-activity',
     name: 'CheckActivity',
@@ -130,7 +136,7 @@ const routes: RouteRecordRaw[] = [
   {
     path: '/container-operation',
     name: 'containerOperation',
-    meta:{title:'容器操作'},
+    meta:{title:'容器移动'},
     component: () => import('@/views/equipment/container/bindUnbind/index.vue')
   },
 ];

+ 842 - 0
src/views/robot/takeDelivery/task/index.vue

@@ -0,0 +1,842 @@
+<template>
+  <div class="container">
+    <van-nav-bar title="智能仓收货" left-arrow fixed placeholder @click-left="goBack">
+      <template #left>
+        <van-icon name="arrow-left" size="25" />
+        <div style="color: #fff">返回</div>
+      </template>
+    </van-nav-bar>
+    <div class="take-delivery">
+      <div class="take-info">
+        <div class="take-info-no">
+          <div class="info-no-title">
+            <div>任务号:{{ taskInfo.taskNo || '--' }}</div>
+            <div>
+              <van-button type="primary" size="mini" plain @click="switchTask">切换任务</van-button>
+            </div>
+          </div>
+          <div class="info-no-tips">
+            <div>货主:<span style="color: #333;font-weight: bold;">{{ taskInfo.customerName || '--' }}</span></div>
+            <div>任务数:<span style="color: #0077ff;font-weight: bold;">{{ taskInfo.receivedQty || 0 }}/{{ taskInfo.expectedQty || 0}}</span></div>
+          </div>
+        </div>
+        <div class="take-info-number">
+          <div class="info-number-left">
+            <div class="number-left-box">
+              <div>开始时间:</div>
+              <div class="left-box-title">{{ currentTime }}</div>
+            </div>
+            <div class="number-left-box">
+              <div>已用时:</div>
+              <div class="left-box-title">{{ formattedTime }}</div>
+            </div>
+          </div>
+        </div>
+      </div>
+      <van-progress v-if="taskInfo.receivedQty/taskInfo.expectedQty>=0" :percentage="((taskInfo.receivedQty/taskInfo.expectedQty)*100).toFixed(2)" stroke-width="4" />
+      <div class="take-barcode">
+          <div class="barcode-input">
+            <van-search
+              ref="searchRef"
+              v-model.lazy="searchBarcode"
+              placeholder="请扫描商品条码"
+              @search="_handlerScan(searchBarcode)"
+              label="商品条码:"
+              left-icon=""
+              :class="[scanType===2?'search-input-barcode':'','van-hairline--bottom']"
+              @focus="scanType=2"
+              autocomplete="off"
+              @input="onAsnCancel"
+              @clear="reset"
+            >
+            </van-search>
+          </div>
+        <div class="barcode-input">
+            <van-search
+              ref="containerNoRef"
+              v-model.lazy="containerNo"
+              placeholder="请扫描库位号"
+              @search="_handlerScan(containerNo)"
+              label="&nbsp;&nbsp;&nbsp;&nbsp;库位号:"
+              left-icon=""
+              :class="[scanType===5?'search-input-barcode':'','van-hairline--bottom']"
+              @focus="scanType=5"
+              autocomplete="off"
+              @input="onAsnCancel"
+            >
+            </van-search>
+          </div>
+        <div class="barcode-input">
+          <van-search
+            ref="numberRef"
+            v-model="searchCount"
+            placeholder="请输入收货数量"
+            type="number"
+            label="收货数量:"
+            left-icon=""
+            autocomplete="off"
+            show-action
+            :min="1"
+            :max="asnInfo.asnNo?asnInfo.expectedQuantity-asnInfo.receivedQuantity:10000"
+            @search="isCheck()"
+            :class="[scanType===4?'search-input-barcode':'','van-hairline--bottom']"
+            @focus="scanType=4"
+          >
+            <template #action>
+              <div style="display: flex; align-items: center;flex-direction: column;margin-left: 20px"
+                   v-if="asnInfo.asnNo">
+                <div style="height: 20px;font-size: 12px">已收/预计</div>
+                <div style="font-size: 16px;font-weight: bold">{{ asnInfo.receivedQuantity}}/{{ asnInfo.expectedQuantity }}
+                </div>
+              </div>
+            </template>
+          </van-search>
+        </div>
+      </div>
+      <div class="take-lot" v-if="lotData.length>0">
+        <van-cell-group>
+          <div class="take-lot-title">批次信息</div>
+          <van-cell v-for="(item,i) in lotData" :key="i" :is-link="item.field!=='lotAtt05'"
+                    @click="onLot(item)">
+            <template #title>
+              <van-icon v-if="item.require" name="warning-o" color="#ed6a0c" />
+              <span class="custom-title">{{ item.label }}</span>
+            </template>
+            <template #value>
+              <div>{{ item.mapping }}</div>
+            </template>
+          </van-cell>
+        </van-cell-group>
+      </div>
+      <div class="take-button">
+        <van-button type="primary" size="large" round style="height: 36px" @click="onConfirm">完成收货</van-button>
+      </div>
+    </div>
+  </div>
+  <!-- 条码输入组件 -->
+  <input-barcode :back="back" @setBarcode="setBarcode" ref="inputBarcodeRef"  />
+  <!--  单据选择-->
+  <van-action-sheet v-model:show="asnDetailsTrueFalseBy" cancel-text="取消" description="请选择具体单据" close-on-click-action>
+    <van-cell-group>
+      <van-cell v-for="item in asnDetailsList" @click="onDetailActive(item)">
+        <template #title>
+          {{ item.asnNo }}({{ item.customerId }}-{{ item.expectedQuantity }}件)
+        </template>
+      </van-cell>
+    </van-cell-group>
+  </van-action-sheet>
+  <!--  商品物理属性-->
+  <attribute ref="attributeRef" @set-attribute="setAttribute" />
+  <!--  商品批次属性-->
+  <lot-date ref="lotDateRef" @select-lot-date="selectLotDate" />
+  <!--  唯一码-->
+  <unique-code-input ref="uniqueCodeRef"
+                     v-model:uniqueCodeList="uniqueCodeList"
+                     v-model:scanType="scanType"
+                     v-model:checkAllType="checkAllType"
+                     :searchCount="searchCount"
+                     :asnInfo="asnInfo"
+                     @setUniqueCode="onConfirm"
+
+  />
+  <van-action-sheet
+    v-model:show="lotQualityTrueFalseBy"
+    cancel-text="取消"
+    close-on-click-action
+    description="请选择质量状态"
+  >
+    <van-cell-group>
+      <van-cell v-for="(value,key) in lotQualityMap" @click="onSelectLotQuality(key)">
+        <template #title>
+          {{value}}
+        </template>
+      </van-cell>
+    </van-cell-group>
+  </van-action-sheet>
+</template>
+
+<script setup>
+import { onMounted, onUnmounted, ref } from 'vue'
+import { androidFocus, getHeader, goBack, scanError, scanSuccess } from '@/utils/android'
+import InputBarcode from '@/views/outbound/picking/components/InputBarcode.vue'
+import { closeListener, openListener, scanInit } from '@/utils/keydownListener'
+import { useRouter } from 'vue-router'
+import {
+  calculateShelfLife, getCommodityRule,
+  getIReceivingTask,
+  getProductAttribute, getProductLot,
+  getReceivingAsnDetails, setBotReceiving,
+  setProductAttribute,
+} from '@/api/takeDelivery/index'
+import { closeLoading, showLoading } from '@/utils/loading'
+import { useStore } from '@/store/modules/user'
+import { showNotify, showToast } from 'vant'
+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'
+import { getCurrentTime } from '@/utils/date'
+
+const router = useRouter()
+const store = useStore()
+try {
+  getHeader()
+  androidFocus()
+} catch (error) {
+  router.push('/login')
+}
+const warehouse = store.warehouse
+//开单任务号
+const taskNo = ref('')
+//容器号
+const containerNo = ref('')
+//商品条码
+const searchBarcode = ref('')
+//收货数量
+const searchCount = ref('')
+//收货详情
+const taskInfo = ref({ receivedQty: 0, expectedQty: 0 })
+//开始时间
+const currentTime = ref('--')
+const scanType = ref(2)
+
+const type=localStorage.getItem('checkAllType')?JSON.parse(localStorage.getItem('checkAllType')):true
+const checkAllType=ref(type)
+// 页面初始化
+onMounted(() => {
+  openListener()
+  scanInit(_handlerScan)
+  loadData()
+
+})
+/**
+ * 计算时分秒
+ */
+// 时器的总秒数
+let totalSeconds = ref(0)
+//时分秒
+const formattedTime = ref('00:00:00')
+let windowTimer = null // 计时器的引用
+const updateFormattedTime = () => {
+  let hours = Math.floor(totalSeconds.value / 3600)
+  let minutes = Math.floor((totalSeconds.value % 3600) / 60)
+  let seconds = totalSeconds.value % 60
+  formattedTime.value = `${String(hours).padStart(2, '0')}:${String(minutes).padStart(2, '0')}:${String(seconds).padStart(2, '0')}`
+}
+// 启动计时器
+const startTimer = () => {
+  if (!windowTimer) {
+    windowTimer = setInterval(() => {
+      totalSeconds.value++
+      updateFormattedTime()
+    }, 1000)
+  }
+}
+
+// 停止计时器
+const stopTimer = () => {
+  if (windowTimer) {
+    clearInterval(windowTimer)
+    windowTimer = null
+  }
+}
+
+const back = ref(true)
+const inputBarcodeType = ref('task')
+//输入框组件
+const inputBarcodeRef = ref(null)
+const oldSearchBarcode = ref('')
+// 设置容器号
+const setBarcode = (code, type) => {
+  if (inputBarcodeType.value === 'lot') {
+    lotData.value.forEach((lot) => {
+      if (lot.field == lotField.value) {
+        lot.mapping = code
+      }
+    })
+    return
+  }
+  showLoading()
+  if(!type){ //切换任务时初始化计时器
+    stopTimer()
+    formattedTime.value="00:00:00"
+    totalSeconds.value=0
+  }
+  getIReceivingTask({ taskNo:code,version:'V6' }).then(res=>{
+    back.value = true
+    if(res.data.receivedQty==res.data.expectedQty && res.data.expectedQty>0 ){
+      if(type){
+        reset()
+        taskNo.value=''
+        taskInfo.value={}
+        switchTask()
+      }else {
+        taskInfo.value=res.data
+        taskNo.value=code
+      }
+      containerNo.value=''
+      stopTimer()
+
+    }else {
+      if(!type){//切换任务成功重启计时器
+        currentTime.value=getCurrentTime()
+        startTimer()
+        containerNo.value=''
+      }
+      taskInfo.value=res.data
+      taskNo.value=code
+    }
+    uniqueCodeList.value=[]
+    scanSuccess()
+  }).catch(err=>{
+    inputBarcodeRef.value?.show('', '请扫描开单任务号',err.message)
+    scanError()
+  }).finally(()=>{
+    reset()
+    closeLoading()
+  })
+}
+// setBarcode('BSSH20250605000006')
+
+//切换任务
+const switchTask = () => {
+  inputBarcodeType.value = 'switchTask'
+  back.value = false
+  inputBarcodeRef.value?.show('', `请扫描开单任务号`,'')
+}
+
+//asn单多条明细展示
+const asnDetailsTrueFalseBy = ref(false)
+const asnDetailsList = ref([])
+const asnInfo = ref({})
+const reset = () => {
+  asnInfo.value = {}
+  lotData.value = []
+  searchCount.value = ''
+  searchBarcode.value = ''
+  oldSearchBarcode.value = ''
+  containerNo.value=''
+  uniqueCodeList.value = []
+}
+// 选择单据
+const onDetailActive = (item) => {
+  asnInfo.value = item
+  asnDetailsTrueFalseBy.value = false
+  searchCount.value=1
+  scanType.value=5
+  // searchCount.value = asnInfo.value.expectedQuantity - asnInfo.value.receivedQuantity
+  _getProductAttribute(item)
+  _getProductLot(item)
+  _getCommodityRule(item)
+}
+const onAsnCancel = () => {
+  if (searchBarcode.value === '' || (oldSearchBarcode.value.length != searchBarcode.value.length && oldSearchBarcode.value != '')) {
+    asnInfo.value = {}
+    lotData.value = []
+    searchCount.value = ''
+    containerNo.value=''
+  }
+}
+const uniqueCodeList = ref([])
+
+// 扫描条码监听
+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 => {
+      uniqueCodeList.value=[]
+      asnDetailsList.value = res.data
+      if (res.data.length > 0) {
+        scanSuccess()
+        closeLoading()
+        if (res.data.length == 1) {
+          const item = res.data[0]
+          asnInfo.value = item
+          // searchCount.value = item.expectedQuantity - item.receivedQuantity
+          searchCount.value=1
+          _getProductAttribute(item)
+          _getProductLot(item)
+          _getCommodityRule(item)
+          scanType.value=5
+        }
+        if (res.data.length > 1) {
+          asnInfo.value = {}
+          lotData.value = []
+          searchCount.value = ''
+          uniqueCodeList.value = []
+          asnDetailsTrueFalseBy.value = true
+        }
+      } else {
+        scanError()
+        showNotify({ type: 'danger', duration: 3000, message: `暂未查询到条码《${code}》信息请重试` })
+        reset()
+        closeLoading()
+      }
+    }).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))) {
+          scanSuccess();
+          uniqueCodeRef.value.uniqueCodeScanType = 'unique'
+          uniqueCodeRef.value.uniqueBarcode = code
+          return;
+        } else {
+          showNotify({ type: 'danger', duration: 3000, message: `${code}-商品条码不匹配,请重新扫描` })
+          uniqueCodeRef.value.uniqueBarcode = ''
+          scanError();
+          return;
+        }
+      }
+      // 如果是通过唯一码扫描,并且没有扫描条码
+      if (uniqueCodeScanType === 'unique' && ( uniqueCodeRef.value.uniqueBarcode == '' && checkAllType.value)) {
+        showNotify({ type: 'danger', duration: 3000, message: '请先扫描商品条码' });
+        uniqueCodeRef.value.uniqueCodeScanType = 'barcode';
+        scanError();
+        return;
+      }
+      const uniqueRegExp = uniqueRuleMap.value['sku'] ? uniqueRuleMap.value['sku'] : uniqueRuleMap.value['all']
+      const isValidCode = new RegExp(uniqueRegExp).test(code)
+      if (!isValidCode) {
+        scanError()
+        showNotify({ type: 'danger', duration: 3000, message: `唯一码《${code}》不符合规则、请重新扫描` })
+        return
+      }
+      if (uniqueCodeList.value.includes(code)) {
+        scanError()
+        showNotify({ type: 'danger', duration: 3000, message: `唯一码《${code}》已存在列表内请重新扫描` })
+        return
+      }
+      scanSuccess()
+      uniqueCodeList.value.unshift(code)
+      uniqueCodeRef.value.uniqueBarcode=''
+      if(checkAllType.value){
+        uniqueCodeRef.value.uniqueCodeScanType='barcode'
+      }else {
+        uniqueCodeRef.value.uniqueCodeScanType='unique'
+      }
+
+    }
+  }else if(scanType.value==5){
+    containerNo.value=barcodeToUpperCase(code)
+    scanSuccess()
+    // isCheck()
+  }
+}
+/**
+ * 物理属性
+ */
+const attributeRef = ref(null)
+const attributeMap = ref({})
+const attributeTrueFalseBy = ref(true)
+// 获取商品物理属性
+const _getProductAttribute = (item) => {
+  const params = { warehouse: item.warehouse, owner: item.customerId, barcode: item.sku }
+  getProductAttribute(params).then(res => {
+    attributeMap.value = res.data
+    const isAttributeInfo = isAttribute(res.data)
+    if (isAttributeInfo.length > 0) {
+      attributeTrueFalseBy.value = false
+      attributeRef.value?.show(isAttributeInfo, res.data)
+    } else {
+      attributeTrueFalseBy.value = true
+    }
+  })
+}
+// 设置商品物理属性
+const setAttribute = (data) => {
+  const params = { warehouse, owner: taskInfo.value.customerId, sku: attributeMap.value.sku }
+  showLoading()
+  setProductAttribute(params, { ...attributeMap.value, ...data }).then(res => {
+    showToast({ duration: 3000, message: '商品物理属性设置成功' })
+    attributeTrueFalseBy.value = true
+    scanSuccess()
+  }).catch(err => {
+    closeLoading()
+    scanError()
+  })
+}
+/**
+ * 物理属性 end
+ */
+
+/**
+ * 商品批次属性
+ */
+// 获取商品批次属性
+const lotData = ref([])
+const _getProductLot = (item) => {
+  const params = { warehouse: item.warehouse, owner: item.customerId, barcode: item.sku }
+  getProductLot(params).then(res => {
+    res.data.forEach((lot) => {
+      const lotField = lot.field
+      if (lotField.startsWith('lotAtt') && lotField.length === 8) {
+        lot.mapping = item[lotField]
+      }
+    })
+    lotData.value = res.data
+    _calculateShelfLife(item, lotData.value)
+  })
+}
+// 计算效期
+const _calculateShelfLife = (item, lotData) => {
+  if ((item.lotAtt01 && item.lotAtt02) || (!item.lotAtt01 && !item.lotAtt02)) return
+  const params = {
+    customer: item.customerId,
+    barcode: item.sku,
+    date: item.lotAtt01 || item.lotAtt02,
+    isExpiryDate: item.lotAtt01 ? true : false,
+  }
+  calculateShelfLife(params).then(date => {
+    lotData.forEach((lot) => {
+      if ((lot.field === 'lotAtt01' && !params.isExpiryDate) ||
+        (lot.field === 'lotAtt02' && params.isExpiryDate)) {
+        lot.mapping = date.data
+      }
+    })
+  })
+}
+//日期选择
+const lotField = ref('')
+const lotDateRef = ref(null)
+const lotQualityTrueFalseBy=ref(false)
+const lotQualityMap=ref({})
+const onLot = (item) => {
+  lotField.value = item.field
+  if (item.field == 'lotAtt05' ) return
+  if ( item.field == 'lotAtt08'){
+    lotQualityMap.value=JSON.parse(item.format)
+    lotQualityTrueFalseBy.value = true
+    return
+  }
+  if (item.type == 'Date') {
+    lotDateRef.value?.show(item.label, item.mapping)
+    return
+  }
+  if (item.type == 'String') {
+    inputBarcodeType.value = 'lot'
+    back.value = false
+    inputBarcodeRef.value?.show('', `请扫描${item.label}`,'')
+    return
+  }
+}
+//设置质量状态
+const onSelectLotQuality=(key)=>{
+  lotData.value.forEach((lot) => {
+    if (lot.field == lotField.value) {
+      lot.mapping = key
+    }
+  })
+  lotQualityTrueFalseBy.value=false
+}
+
+// 设置日期
+const selectLotDate = (date) => {
+  const lotMap = toMap(lotData.value, 'field', 'mapping')
+  if ((lotField.value === 'lotAtt01' || lotField.value === 'lotAtt02') &&
+    lotMap['lotAtt01'] == '' || lotMap['lotAtt01'] == null && lotMap['lotAtt02'] == '' || lotMap['lotAtt02'] == null) {
+    const params = {
+      customer: asnInfo.value.customerId,
+      barcode: asnInfo.value.sku,
+      date,
+      isExpiryDate: lotField.value === 'lotAtt01' ? true : false,
+    }
+    calculateShelfLife(params).then(res => {
+      if(res.data){
+        lotData.value.forEach((lot) => {
+          if (lot.field === 'lotAtt01') {
+            lot.mapping = (lotField.value === 'lotAtt01') ? date : res.data
+          } else if (lot.field === 'lotAtt02') {
+            lot.mapping = (lotField.value === 'lotAtt02') ? date : res.data
+          }
+        })
+      }else {
+        lotData.value.forEach((lot) => {
+          if (lot.field === lotField.value) {
+            lot.mapping = date
+          }
+        })
+      }
+
+    })
+  }
+  lotData.value.forEach((lot) => {
+    if (lot.field === lotField.value) {
+      lot.mapping = date
+    }
+  })
+  inputBarcodeType.value = 'task'
+}
+
+/**
+ * 商品批次属性end
+ */
+/**
+ * 唯一码
+ */
+const uniqueCodeRef = ref(null)
+//规则列表
+const uniqueRuleList = ref([])
+const uniqueRuleMap = ref({})
+// 获取商品规则
+const _getCommodityRule = (item) => {
+  const params = { customer: item.customerId, sku: item.sku, input: 'RECEIVING' }
+  getCommodityRule(params).then(res => {
+    uniqueRuleList.value = res.data
+    res.data.forEach((item, index) => {
+      if (item.sku == '') {
+        item.type = 'all'
+      } else {
+        item.type = 'sku'
+      }
+    })
+    uniqueRuleMap.value = toMap(res.data, 'type', 'uniqueRegExp')
+  })
+}
+/**
+ * 唯一码end
+ */
+const containerNoRef = ref(null)
+const numberRef = ref(null)
+// 完成收货校验
+const isCheck = () => {
+  if (!asnInfo.value.asnNo) {
+    scanError()
+    showToast({ duration: 3000, message: '请先查询商品收货信息' })
+    return false
+  }
+  //商品物理属性判断
+  if (!attributeTrueFalseBy.value) {
+    const isAttributeInfo = isAttribute(attributeMap.value)
+    if (isAttributeInfo.length > 0) {
+      attributeTrueFalseBy.value = false
+      attributeRef.value?.show(isAttributeInfo, attributeMap.value)
+    }
+    return false
+  }
+  // //商品批次属性判断
+  const incompleteLot = lotData.value.find(lot => lot.require && !lot.mapping)
+  if (incompleteLot) {
+    scanError()
+    showToast({ duration: 3000, message: `请先补充${incompleteLot.label}` })
+    return false
+  }
+  const lotMap = toMap(lotData.value, 'field', 'mapping')
+  const productionDate = lotMap['lotAtt01'] ? new Date(lotMap['lotAtt01']) : null
+  const expirationDate = lotMap['lotAtt02'] ? new Date(lotMap['lotAtt02']) : null
+  const currentDate = new Date()
+// 如果存在失效日期
+  if (expirationDate) {
+    // 如果有生产日期,进行有效性检查
+    if (productionDate && expirationDate <= productionDate) {
+      scanError()
+      showToast({ duration: 3000, message: `失效日期不能小于等于生产日期` })
+      return false
+    }
+    // 检查失效日期是否小于当前日期
+    if (expirationDate <= currentDate) {
+      scanError()
+      showToast({ duration: 3000, message: `失效日期不能小于等于当前日期` })
+      return false
+    }
+  }
+  if(productionDate){
+    // 如果有生产日期,进行有效性检查
+    if (expirationDate && productionDate >= expirationDate) {
+      scanError()
+      showToast({ duration: 3000, message: `生产日期不能大于失效日期` })
+      return false
+    }
+    // 检查生产日期是否小于当前日期
+    if (productionDate >= currentDate) {
+      scanError()
+      showToast({ duration: 3000, message: `生产日期不能大于等于当前日期` })
+      return false
+    }
+  }
+  if (searchCount.value == '') {
+    numberRef.value?.focus()
+    scanError()
+    showToast({ duration: 3000, message: '请先输入收货数量' })
+    return false
+  }
+  if (containerNo.value == '') {
+    scanError()
+    containerNoRef.value?.focus()
+    showToast({ duration: 3000, message: '请先扫描库位号' })
+    scanType.value=5
+    return false
+  }
+  // 唯一码收集
+  if (uniqueRuleList.value.length > 0 && uniqueCodeList.value.length != searchCount.value) {
+      scanType.value = 3
+      uniqueCodeRef.value?.show('', '请扫描唯一码', `收货数量:${searchCount.value}`, uniqueRuleMap.value)
+      return false
+  }
+  return true
+}
+// 收货
+const onConfirm = () => {
+  if(isCheck()){
+    const lotMap = toMap(lotData.value, 'field', 'mapping')
+    const { asnLineNo, asnNo, warehouse } = asnInfo.value
+    const data = {
+      asnLineNo,
+      asnNo,
+      containerId: containerNo.value,
+      quantity: searchCount.value,
+      warehouse,
+      serialNos: uniqueCodeList.value.length > 0 ? uniqueCodeList.value : undefined,
+      ...lotMap,
+    }
+    showLoading()
+    inputBarcodeType.value='task'
+    setBotReceiving(data).then(res => {
+      scanSuccess()
+      showNotify({ type: 'success', duration: 3000, message: `${searchBarcode.value}收货完成,请继续收货!`})
+      setBarcode(taskNo.value, '2')
+      reset()
+      taskInfo.value={}
+      scanType.value=2
+      closeLoading()
+    }).catch(err => {
+      if(err.message.includes('序列号已存在')){
+        scanType.value = 3
+        uniqueCodeRef.value?.show('', '请扫描唯一码', `收货数量:${searchCount.value},${err.message}`, uniqueRuleMap.value)
+      }
+      scanError()
+      closeLoading()
+    })
+    }
+}
+
+// 数据刷新
+const loadData = () => {
+  if (!taskNo.value) {
+    inputBarcodeRef.value?.show('', '请扫描开单任务号','')
+    return
+  } else {
+    // currentTime.value=getCurrentTime()
+    // startTimer()
+  }
+}
+onUnmounted(() => {
+  closeListener()
+  stopTimer()
+})
+window.onRefresh = loadData
+
+</script>
+<style scoped lang="sass">
+.take-delivery
+  .take-info
+    padding: 6px 10px
+    background: #e0eeff
+    display: flex
+    flex-direction: column
+    text-align: left
+
+    .take-info-no
+      flex: 1
+
+      .info-no-title
+        font-size: 18px
+        display: flex
+        justify-content: space-between
+        align-items: center
+
+      .info-no-tips
+        font-size: 14px
+        color: #666666
+        display: flex
+        justify-content: space-between
+        padding: 6px 0
+
+    .take-info-number
+      flex: 1
+      border-top: 1.5px solid #ffffff
+      display: flex
+      justify-content: space-between
+      color: #666
+      font-size: 14px
+
+      .info-number-left
+        flex: 1
+        display: flex
+        justify-content: space-between
+        align-items: center
+
+        .number-left-box
+          flex: 1
+          display: flex
+          justify-content: center
+          align-items: center
+
+          .left-box-title
+            font-size: 14px
+            font-weight: bold
+            color: #000
+            line-height: 34px
+
+      .info-number-right
+        width: 0%
+        text-align: center
+
+        .van-search
+          padding: 0
+
+  .take-barcode
+    margin-top: 10px
+    text-align: left
+    background: #FFFFFF
+
+    .barcode-input
+      ::v-deep(.van-search)
+        padding: 0
+
+      ::v-deep(.van-search__field)
+        border-bottom: 2px solid #ffffff
+
+      ::v-deep(.van-search__content)
+        background: #fff
+
+      ::v-deep(.van-field__control)
+        font-size: 15px
+        font-weight: bold
+
+      ::v-deep(.van-search__label)
+        font-size: 15px
+        font-weight: bold
+
+      .search-input-barcode
+        ::v-deep(.van-search__field)
+          border-bottom: 2px solid #0077ff
+          z-index: 2
+
+  .take-lot
+    text-align: left
+    margin-top: 5px
+
+    ::v-deep(.van-cell)
+      padding: 5px 8px
+
+    .take-lot-title
+      font-size: 15px
+      font-weight: bold
+      padding: 0 5px
+      border-left: 3px solid #1989fa
+      color: #333
+      margin-bottom: 3px
+
+  .take-button
+    padding: 20px
+</style>