Ver Fonte

增加组合商品拣货

zhaohuanhuan há 1 ano atrás
pai
commit
78f4e6a312

+ 13 - 6
src/utils/dataType.js

@@ -1,24 +1,31 @@
 
 
-export function toMap(data, key, val, optional = {}) {
-  const map = {}
+export function toMap(data, key, val=undefined, optional = {}) {
+  const map = {};
+
+  // 如果 key 为 null,直接将数组中的每个元素的值都设为 val
   if (key === null) {
   if (key === null) {
-    // 如果 key 为 null,直接将数组中的每个元素的值都设为 val
     data.forEach(item => {
     data.forEach(item => {
-      map[item] = val;
+      // 如果没有传入 val,则将整个 item 作为值
+      map[item] = val !== undefined ? val : item;
     });
     });
     return map;
     return map;
   }
   }
+  // 遍历数据
   data.forEach(item => {
   data.forEach(item => {
     // 如果 optional.type 是 String,则处理字符串转换
     // 如果 optional.type 是 String,则处理字符串转换
     if (optional.type === String) {
     if (optional.type === String) {
       item[key] = item[key] + '';  // 转为字符串
       item[key] = item[key] + '';  // 转为字符串
       item[key] = item[key].trim(); // 去除空格
       item[key] = item[key].trim(); // 去除空格
     }
     }
-    // 按照 key 和 val 构建 map
-    map[item[key]] = item[val];
+
+    // 如果没有传入 val,则将 item 本身作为值
+    map[item[key]] = val !== undefined ? item[val] : item;
   });
   });
+
   return map;
   return map;
 }
 }
+
+
  export function barcodeToUpperCase(code){
  export function barcodeToUpperCase(code){
    if (/[a-zA-Z]/.test(code)) {
    if (/[a-zA-Z]/.test(code)) {
      return  code.toUpperCase();  // 强制转换为大写字母
      return  code.toUpperCase();  // 强制转换为大写字母

+ 1 - 1
src/views/login/login.vue

@@ -21,7 +21,7 @@ const count = ref(0);
 const store = useStore()
 const store = useStore()
 const onConfirm = async () => {
 const onConfirm = async () => {
   const { data } = await login(params)
   const { data } = await login(params)
-  data.warehouse='WH01'
+  data.warehouse='WH99'
   store.setToken(data)
   store.setToken(data)
   router.push('/picking')
   router.push('/picking')
 }
 }

+ 11 - 6
src/views/outbound/components/BigPicking.vue

@@ -8,12 +8,16 @@
     <div class="big-task-list" @click.stop>
     <div class="big-task-list" @click.stop>
       <div class="big-task-item" v-for="(item,index) in props.taskDetailList" :key="index" >
       <div class="big-task-item" v-for="(item,index) in props.taskDetailList" :key="index" >
         <div class="big-task-content"  >
         <div class="big-task-content"  >
-          <div class="big-content">{{item.orderNo}}</div>
-          <div class="big-carrier"><van-notice-bar :background="'none'" :speed="10" :text="item.carrierName" /></div>
-          <div class="big-content" :style="item.hours>=2?'color:#ee0a24;font-weight: 500':''">{{item.totalItemNum}}<span style="font-size: 12px">件</span></div>
+          <div class="big-content" :style="item.hours>=2?'color:#ee0a24;font-weight: 500':''">{{item.orderNo}}</div>
+          <div  class="big-carrier" v-if="item.availableQty===item.totalItemNum"><van-notice-bar :background="'none'" :speed="10" color="#333" :text="item.carrierName" /></div>
+          <div class="big-content"><span style="font-size: 12px">共</span>{{item.totalItemNum}}<span style="font-size: 12px">件</span></div>
+          <div class="big-content" v-if="item.availableQty!==item.totalItemNum"><span style="font-size: 12px">剩</span>{{item.availableQty}}<span style="font-size: 12px">件</span></div>
+        </div>
+        <div style="margin-top: -5px" v-if="item.availableQty!==item.totalItemNum">
+          <van-notice-bar :background="'none'" style="font-size: 12px" color="#333" :speed="10" :text="item.carrierName" />
         </div>
         </div>
         <div class="big-task-button">
         <div class="big-task-button">
-          <div class="big-button" @click="onTypeOrder(item,'LOCATION_PICK')"  >按库位查看</div>
+          <div class="big-button" @click="onTypeOrder(item,'LOCATION_PICK')">按库位查看</div>
           <div class="big-button" @click="onTypeOrder(item,'AISLE_PICK')">按巷道查看</div>
           <div class="big-button" @click="onTypeOrder(item,'AISLE_PICK')">按巷道查看</div>
           <div class="big-button" @click="onTypeOrder(item,'ITEM_PICK')" >按商品查看</div>
           <div class="big-button" @click="onTypeOrder(item,'ITEM_PICK')" >按商品查看</div>
         </div>
         </div>
@@ -29,11 +33,11 @@
   >
   >
     <div class="sub-task-list" >
     <div class="sub-task-list" >
       <div style="display: flex;justify-content: space-between;">
       <div style="display: flex;justify-content: space-between;">
-        <div><van-checkbox  class="sub-task-checkbox" v-model="isCheckAll"  :indeterminate="isIndeterminate"  @change="checkAllChange">全选</van-checkbox></div>
         <div  v-if="taskType==='ITEM_PICK'" >
         <div  v-if="taskType==='ITEM_PICK'" >
           <van-tag type="primary" :plain="sortType==='number'"   @click="onSort('sql')">按排序规则</van-tag>
           <van-tag type="primary" :plain="sortType==='number'"   @click="onSort('sql')">按排序规则</van-tag>
           <van-tag type="primary" :plain="sortType==='sql'"  @click="onSort('number')">按库位数量</van-tag>
           <van-tag type="primary" :plain="sortType==='sql'"  @click="onSort('number')">按库位数量</van-tag>
         </div>
         </div>
+        <div><van-checkbox  class="sub-task-checkbox" v-model="isCheckAll"  :indeterminate="isIndeterminate"  @change="checkAllChange">全选</van-checkbox></div>
       </div>
       </div>
       <van-checkbox-group  v-model="checkedResult" @change="checkedChange">
       <van-checkbox-group  v-model="checkedResult" @change="checkedChange">
         <van-checkbox class="sub-task-checkbox" v-for="(item,index) in typeTaskList" :key="index" :name="item"  :disabled="(item.allowPick===false && taskType==='AISLE_PICK') || item.status!==40" >
         <van-checkbox class="sub-task-checkbox" v-for="(item,index) in typeTaskList" :key="index" :name="item"  :disabled="(item.allowPick===false && taskType==='AISLE_PICK') || item.status!==40" >
@@ -233,13 +237,14 @@ defineExpose({show})
     .big-task-content
     .big-task-content
       display: flex
       display: flex
       align-items: center
       align-items: center
+      justify-content: space-between
       padding: 5px 10px
       padding: 5px 10px
       font-size: 14px
       font-size: 14px
       font-weight: bold
       font-weight: bold
       .big-carrier
       .big-carrier
         width: 30%
         width: 30%
       .big-content
       .big-content
-        flex: 1
+        //flex: 1
     .big-task-button
     .big-task-button
       font-size: 14px
       font-size: 14px
       font-weight: bold
       font-weight: bold

+ 86 - 40
src/views/outbound/picking/list/index.vue

@@ -106,6 +106,7 @@
     <input-barcode ref="inputBarcodeRef" @setBarcode="_handlerScan" />
     <input-barcode ref="inputBarcodeRef" @setBarcode="_handlerScan" />
     <van-floating-bubble v-if="locationList.length>0"  :gap="50" axis="xy" magnetic="x"  @click="onContainerNo(containerNo===''?2:scanType)">容器</van-floating-bubble>
     <van-floating-bubble v-if="locationList.length>0"  :gap="50" axis="xy" magnetic="x"  @click="onContainerNo(containerNo===''?2:scanType)">容器</van-floating-bubble>
     <lot-att ref="lotAttRef" />
     <lot-att ref="lotAttRef" />
+    <barcode-combine ref="barcodeCombineRef" @setCombine="setCombine" :container="containerNo" :matched-sku="matchedSku" />
   </div>
   </div>
 </template>
 </template>
 <script lang="ts" setup>
 <script lang="ts" setup>
@@ -124,14 +125,16 @@ import { goBack, getHeader, playVoicePickNum, scanError, scanSuccess } from '@/u
 import { closeListener, openListener, scanInit } from '@/utils/keydownListener'
 import { closeListener, openListener, scanInit } from '@/utils/keydownListener'
 import PickingNoInput from '@/views/outbound/components/PickingNoInput.vue'
 import PickingNoInput from '@/views/outbound/components/PickingNoInput.vue'
 import ContainerNoInput from '@/views/outbound/components/ContainerNoInput.vue'
 import ContainerNoInput from '@/views/outbound/components/ContainerNoInput.vue'
+import BarcodeCombine from '@/views/outbound/components/BarcodeCombine.vue'
 import { formatDateTime } from '@/utils/date'
 import { formatDateTime } from '@/utils/date'
 import { isLot } from '@/views/outbound/picking/list/hooks/lotNum'
 import { isLot } from '@/views/outbound/picking/list/hooks/lotNum'
-import { barcodeToUpperCase } from '@/utils/dataType'
+import { barcodeToUpperCase, toMap } from '@/utils/dataType'
 import { containerDef } from '@/views/outbound/picking/list/hooks/containerDef'
 import { containerDef } from '@/views/outbound/picking/list/hooks/containerDef'
 import { getCarrierList } from '@/hooks/basic/carrier'
 import { getCarrierList } from '@/hooks/basic/carrier'
 import { basicStore } from '@/store/modules/basic'
 import { basicStore } from '@/store/modules/basic'
 import InputBarcode from '@/views/outbound/components/InputBarcode.vue'
 import InputBarcode from '@/views/outbound/components/InputBarcode.vue'
 import LotAtt from '@/views/outbound/components/lotAtt.vue'
 import LotAtt from '@/views/outbound/components/lotAtt.vue'
+import { barcodeCombine } from '@/views/outbound/picking/list/hooks/barcodeCombine'
 onUnmounted(() => {
 onUnmounted(() => {
   closeListener()
   closeListener()
 })
 })
@@ -172,6 +175,8 @@ const selectTask=ref([])
 
 
 const scanBarcode=ref('')
 const scanBarcode=ref('')
 const taskItem=ref([])
 const taskItem=ref([])
+//匹配组合商品数据
+const matchedSku=ref([])
 // 切换容器号
 // 切换容器号
 const containerNoInputRef=ref(null)
 const containerNoInputRef=ref(null)
 const onContainerNo=(type)=>{
 const onContainerNo=(type)=>{
@@ -229,7 +234,6 @@ const loadData =  async (pickingCode) => {
     // onContainerNo(2)
     // onContainerNo(2)
   }
   }
 }
 }
-
 // 设置拣货容器
 // 设置拣货容器
 const setContainer=(code,type)=>{
 const setContainer=(code,type)=>{
   containerNo.value=code
   containerNo.value=code
@@ -239,12 +243,6 @@ const setContainer=(code,type)=>{
     onScan(type)
     onScan(type)
   }
   }
 }
 }
-
-// 设置扫码
-const setBarcode=(code)=>{
-
-}
-
 // 获取拣货任务号
 // 获取拣货任务号
 const getPickingCode= async()=>{
 const getPickingCode= async()=>{
   const { pickingCode } = await fetchPickingData(warehouse)
   const { pickingCode } = await fetchPickingData(warehouse)
@@ -316,6 +314,7 @@ const onScan = (type) => {
     scanType.value = type
     scanType.value = type
   })
   })
 }
 }
+const barcodeCombineRef=ref(null)
 //扫描条码监听
 //扫描条码监听
 const _handlerScan=(code)=> {
 const _handlerScan=(code)=> {
   if(scanType.value===1){
   if(scanType.value===1){
@@ -367,18 +366,42 @@ const _handlerScan=(code)=> {
           onCount(locationList.value[activeIndex.value].list[0],0)
           onCount(locationList.value[activeIndex.value].list[0],0)
         },200)
         },200)
     }else{
     }else{
-      scanError()
-      // const params = {
-      //
-      // }
-      // getListCombineSku()
-      showToast({duration:5000,message:'无效条码!请检查扫描条码'})
-
+      matchedSku.value=[]
+      // scanError()
+      // showToast({duration:5000,message:'无效条码!请检查扫描条码'})
+      getListCombineSku({combineSku:code, workEnvironment:'picking'}).then(res=>{
+        if(res.data.length>0){
+          const combineSkuMap=toMap(res.data,'barcode')
+          const matchedSkuList=barcodeCombine(modelLocative.list,combineSkuMap)
+          if(matchedSkuList.length>0){
+            if(modelLocative.list.length==matchedSkuList.length){
+              matchedSku.value=matchedSkuList
+              barcodeCombineRef.value.show()
+            }else{
+              scanError()
+              showDialog({
+                title:'温馨提示',
+                message:'组合商品与拣货任务匹配,请检查组合商品配置!'
+              })
+            }
+          }else {
+            scanError()
+            showDialog({
+              title:'温馨提示',
+              message:'组合商品与拣货任务匹配,请检查组合商品配置!'
+            })
+          }
+        }else {
+          scanError()
+          showToast({duration:5000,message:'无效条码!请检查扫描条码'})
+        }
+      })
     }
     }
   }
   }
 }
 }
+
 // 进行条件验证
 // 进行条件验证
-const validate = (data) => {
+const validate = (data,type) => {
   if (containerNo.value === '') {
   if (containerNo.value === '') {
     showToast({duration:5000,message:'请先扫描拣货容器'})
     showToast({duration:5000,message:'请先扫描拣货容器'})
     return false;
     return false;
@@ -401,12 +424,13 @@ const validate = (data) => {
     messageTips.value='拣货数量不能大于所需数量'
     messageTips.value='拣货数量不能大于所需数量'
     return false;
     return false;
   }
   }
-  if (isLot(selectTask.value, [data])) {
+  if (type==0 && isLot(selectTask.value, [data])) {
     messageTips.value='当前容器下已有其他批次产品,请更换容器号'
     messageTips.value='当前容器下已有其他批次产品,请更换容器号'
     scanBarcode.value=''
     scanBarcode.value=''
     showToast({duration:5000,message:'当前容器下已有其他批次产品,请更换容器号'})
     showToast({duration:5000,message:'当前容器下已有其他批次产品,请更换容器号'})
     return false;
     return false;
   }
   }
+
   return true;
   return true;
 }
 }
 //输入数量
 //输入数量
@@ -422,35 +446,57 @@ const onCount=(item,type)=>{
     data.quantity=0
     data.quantity=0
   }
   }
   // 验证数据的有效性
   // 验证数据的有效性
-  if (!validate(data)) return;
+  if (!validate(data,type)) return;
   if(type!==0){
   if(type!==0){
     jumpLoading.value=true
     jumpLoading.value=true
   }
   }
+  _setPickingDetail(params,type)
+}
+//组合商品
+const setCombine=(data)=>{
+  if (isLot(selectTask.value, data)) {
+    messageTips.value='当前容器下已有其他批次产品,请更换容器号'
+    scanBarcode.value=''
+    showToast({duration:5000,message:'当前容器下已有其他批次产品,请更换容器号'})
+    return false;
+  }
+  _setPickingDetail(data,0)
+}
+const _setPickingDetail=(params,type)=>{
   //扣减库存
   //扣减库存
   setPickingDetail(params).then((res)=>{
   setPickingDetail(params).then((res)=>{
-    jumpLoading.value=false
-    if(res.data==false){
+    jumpLoading.value = false;
+    if (res.data == false) {
       showDialog({
       showDialog({
-        title:'温馨提示',
-        message:'该库位条码存在取消单,任务已被刷新,请将当前货品归还原库位'
+        title: '温馨提示',
+        message: '该库位条码存在取消单,任务已被刷新,请将当前货品归还原库位'
       }).then(() => {
       }).then(() => {
-        loadData(pickingNo.value)
-      })
-      return
+        loadData(pickingNo.value);
+      });
+      return;
     }
     }
     //任务行号相同说明重复执行
     //任务行号相同说明重复执行
-    if(!selectTask.value.find(task => task.line === data.line)){
-      const task={
-        barcode: data.barcode,
-        location:data.location,
-        lotNum: data.lotNum,
-        line:data.line,
-        operationTime: data.operationTime,
-        container:data.container,
-        quantity:data.quantity
-      }
-      selectTask.value.push(task)
-      locationList.value[activeIndex.value].list[0].operationTime=params[0].operationTime
+    if (!selectTask.value.find(task => params.some(param => task.line === param.line))) {
+      // 遍历 params 数组并处理每个元素
+      params.forEach((param) => {
+        const task = {
+          barcode: param.barcode,
+          location: param.location,
+          lotNum: param.lotNum,
+          line: param.line,
+          operationTime: param.operationTime,  // 使用每个对象的 operationTime
+          container: param.container,
+          quantity: param.quantity
+        };
+        selectTask.value.push(task);
+      })
+      // 更新 locationList 中的 operationTime
+      params.forEach((param, index) => {
+        if (locationList.value[activeIndex.value].list[index]) {
+          locationList.value[activeIndex.value].list[index].operationTime = param.operationTime;
+          locationList.value[activeIndex.value].list[index].count = param.quantity;
+        }
+      });
     }
     }
     //验证库位里的所有商品是否都存在拣货时间
     //验证库位里的所有商品是否都存在拣货时间
     const allOperationTimeExist = locationList.value[activeIndex.value].list.every(item => item.operationTime);
     const allOperationTimeExist = locationList.value[activeIndex.value].list.every(item => item.operationTime);
@@ -501,7 +547,7 @@ const result=()=>{
 // 跳过拣货
 // 跳过拣货
 const jump=(item)=>{
 const jump=(item)=>{
   item.quantity=0
   item.quantity=0
-  if (!validate(item)) return;
+  if (!validate(item,1)) return;
   showConfirmDialog({
   showConfirmDialog({
     title:'温馨提示',
     title:'温馨提示',
     message:'您正在进行缺货跳过操作,是否继续'
     message:'您正在进行缺货跳过操作,是否继续'
@@ -609,7 +655,7 @@ const onRefresh = () => {
     .left
     .left
       background: #f2f8fe
       background: #f2f8fe
       padding: 2px 10px
       padding: 2px 10px
-      height: 83.1vh
+      height: 80vh
       overflow: scroll
       overflow: scroll
       box-sizing: border-box
       box-sizing: border-box
 
 
@@ -634,7 +680,7 @@ const onRefresh = () => {
         color: #fff
         color: #fff
 
 
     .right
     .right
-      height: 83.1vh
+      height: 80vh
       overflow: scroll
       overflow: scroll
       box-sizing: border-box
       box-sizing: border-box
       text-align: left
       text-align: left

+ 2 - 2
src/views/outbound/picking/task/index.vue

@@ -404,9 +404,9 @@ const createPicking = () => {
     // uidMap:Object.keys(uidMap).length !== 0?uidMap:undefined,
     // uidMap:Object.keys(uidMap).length !== 0?uidMap:undefined,
   }
   }
   showLoading()
   showLoading()
-  createPickingTask(params).then(data => {
+  createPickingTask(params).then(res => {
     closeLoading()
     closeLoading()
-    router.push('/picking')
+    router.push({name:'PickingList',query: { code:res.data }})
     loadData()
     loadData()
   }).catch(err => {
   }).catch(err => {
     closeLoading()
     closeLoading()