Ver Fonte

手持-海康初始化

zhaohuanhuan há 9 meses atrás
pai
commit
374f3ecc2e

+ 99 - 0
src/api/haikang/index.ts

@@ -0,0 +1,99 @@
+// @ts-ignore
+import request from '@/utils/request'
+// @ts-ignore
+import {getWaitPutawayListType, getRecommendedLocationType,setBindAllocateWallType } from '@/types/haikang'
+/**
+ * 上架任务列表
+ * @param params
+ */
+export function getWaitPutawayList(params:getWaitPutawayListType) {
+  return request({
+    url: 'api/wms/inbound/task/pagination',
+    method: 'get',
+    params
+  })
+}
+/**
+ * 推荐库位
+ * @param params
+ */
+export function getRecommendedLocation(params:getRecommendedLocationType) {
+  return request({
+    url: '/api/wms/inbound/recommended-location',
+    method: 'get',
+    params
+  })
+}
+/**
+ * 商品绑定分拨墙格口
+ * @param data
+ */
+export function setBindAllocateWall(data:setBindAllocateWallType) {
+  return request({
+    url: '/api/wms/return/inventory/bindAllocateWallCompartment',
+    method: 'post',
+    data
+  })
+}
+
+/**
+ * 根据库位和商品编号查询上架信息
+ * @param params
+ */
+export function getShelveItemInfo(params:any) {
+  return request({
+    url: '/api/wms/return/inventory/getShelveItemInfo',
+    method: 'post',
+    params
+  })
+}
+
+/**
+ * 上架
+ * @param params
+ */
+export function setBoxInboundInventory(data:any) {
+  return request({
+    url: '/api/wms/return/inventory/boxInboundInventory',
+    method: 'post',
+    data
+  })
+}
+
+/**
+ * 料箱回库
+ * @param params
+ */
+export function boxReturn(params:any) {
+  return request({
+    url: '/api/wms/return/inventory/boxReturn',
+    method: 'post',
+    params
+  })
+}
+
+/**
+ * 调空料箱并回库
+ * @param data
+ */
+export function outboundEmptyBoxAndBindTask(data:any) {
+  return request({
+    url: '/api/wms/return/inventory/outboundEmptyBoxAndBindTask',
+    method: 'post',
+    data
+  })
+}
+/**
+ * 海康-入库
+ * @param data
+ */
+export function createHikBoxInboundTask(data:any) {
+  return request({
+    url: '/api/wms/robot/task/createHikBoxInboundTask',
+    method: 'post',
+    data
+  })
+}
+
+
+

+ 18 - 0
src/router/index.ts

@@ -61,6 +61,24 @@ const routes: RouteRecordRaw[] = [
     meta:{title:'宝时丰收'},
     meta:{title:'宝时丰收'},
     component: () => import('@/views/inbound/TakeDelivery/task/index.vue')
     component: () => import('@/views/inbound/TakeDelivery/task/index.vue')
   },
   },
+  {
+    path: '/hik-putaway-allocation',
+    name: 'HikPutawayAllocation',
+    meta:{title:'海康上架-调度'},
+    component: () => import('@/views/haikang/putaway/dispatch/index.vue')
+  },
+  {
+    path: '/hik-putaway',
+    name: 'HikPutaway',
+    meta:{title:'海康上架'},
+    component: () => import('@/views/haikang/putaway/putaway/index.vue')
+  },
+  {
+    path: '/hik-box-return',
+    name: 'HikBoxReturn',
+    meta:{title:'海康-入库'},
+    component: () => import('@/views/haikang/boxReturn/boxReturn/index.vue')
+  },
 
 
 ];
 ];
 
 

+ 83 - 0
src/types/haikang.ts

@@ -0,0 +1,83 @@
+
+/**
+ * 上架任务列表
+ * @param warehouse 仓库
+ */
+export interface getWaitPutawayListType {
+  /**
+   * 容器号
+   */
+  container?: string;
+  /**
+   * 页数
+   */
+  page?: number;
+  /**
+   * 条目数
+   */
+  size?: number;
+  /**
+   * 是否完成
+   */
+  status?: boolean;
+  /**
+   * 仓库
+   */
+  warehouse?: string;
+  [property: string]: any;
+}
+
+/**
+ * 推荐库位
+ * @param warehouse 仓库
+ */
+export interface getRecommendedLocationType {
+  /**
+   * 批次号
+   */
+  lotNum?: string;
+  /**
+   * 货主编号
+   */
+  owner?: string;
+  /**
+   * 仓库
+   */
+  warehouse?: string;
+  [property: string]: any;
+}
+
+export interface setBindAllocateWallType {
+  /**
+   * 仓库
+   */
+  warehouse: string;
+  /**
+   * 商品条码
+   */
+  barcode: string;
+  /**
+   * 格口号
+   */
+  bin: string;
+  /**
+   * 收货容器号
+   */
+  container: string;
+  /**
+   * 分拨墙
+   */
+  equipment: string;
+  /**
+   * 库位
+   */
+  location: string[];
+  /**
+   * 批次号
+   */
+  lotNum?: string;
+  sku?: string;
+  barcodeAs?: string;
+  [property: string]: any;
+}
+

+ 159 - 0
src/views/haikang/boxReturn/boxReturn/index.vue

@@ -0,0 +1,159 @@
+
+<template>
+  <div class="box-return">
+    <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="box-return-content">
+      <div class="content-tips">
+        <div style="flex: 1"><van-notice-bar left-icon="volume-o">{{ tips }}</van-notice-bar></div>
+      </div>
+        <div class="content-code">
+          <div class="barcode-input">
+            <van-search
+              ref="boxRef"
+              v-model="scanBox"
+              placeholder="请扫描料箱编码"
+              @search="_handlerScan(scanBox)"
+              label="料箱编码:"
+              left-icon=""
+              :class="[scanType===1?'search-input-barcode':'','van-hairline--bottom']"
+              @focus="scanType=1"
+              autocomplete="off"
+            >
+            </van-search>
+          </div>
+          <div class="barcode-input">
+            <van-search
+              v-model="scanStation"
+              placeholder="请扫描工作站点"
+              @search="_handlerScan(scanStation)"
+              label="工作站点:"
+              left-icon=""
+              :class="[scanType===2?'search-input-barcode':'','van-hairline--bottom']"
+              @focus="scanType=2"
+              autocomplete="off"
+            >
+            </van-search>
+          </div>
+        </div>
+    </div>
+  </div>
+</template>
+<script setup lang="ts">
+import { onMounted, onUnmounted, ref } from 'vue'
+import { getHeader, goBack, scanError, scanSuccess } from '@/utils/android'
+import { closeListener, openListener, scanInit } from '@/utils/keydownListener'
+import { barcodeToUpperCase } from '@/utils/dataType'
+import { showNotify } from 'vant'
+import { createHikBoxInboundTask } from '@/api/haikang'
+import { useStore } from '@/store/modules/user'
+import { closeLoading, showLoading } from '@/utils/loading'
+const tips=ref('请扫描料箱')
+const scanType = ref(1)
+const scanBox=ref('')
+const scanStation=ref('')
+const store = useStore()
+const warehouse = store.warehouse
+try {
+  getHeader()
+} catch (error) {
+}
+// 页面初始化
+onMounted(() => {
+  openListener()
+  scanInit(_handlerScan)
+
+})
+// 扫描条码监听
+const _handlerScan = (code) => {
+  if (scanType.value == 1) {
+    if(barcodeToUpperCase(code).includes('HK')){
+      scanBox.value = code
+      scanType.value=2
+      tips.value='请扫描工作站台'
+    }else {
+      tips.value='请扫描海康料箱'
+      showNotify({ type: 'danger', duration: 3000, message:'请扫描海康料箱' })
+    }
+  }else if(scanType.value == 2){
+    if(!scanBox.value){
+      tips.value='请先扫描料箱编号'
+      scanType.value=1
+      showNotify({ type: 'danger', duration: 3000, message:'请先扫描料箱编号' })
+      return
+    }
+    if(code){
+      scanStation.value = code
+      console.log('入库')
+      _createHikBoxInboundTask()
+    }
+  }
+}
+const _createHikBoxInboundTask=()=>{
+  const data={
+    warehouse,
+    boxCode:scanBox.value,
+    stationCode:scanStation.value,
+    deviceType:'HIK_INBOUND_STATION'
+  }
+  showLoading()
+  createHikBoxInboundTask(data).then(res=>{
+    if(res.data){
+      tips.value='请继续扫描料箱编号'
+      scanType.value=1
+      scanBox.value=''
+      scanStation.value=''
+      showNotify({ type: 'success', duration: 3000, message:'料箱入库成功,请继续扫描需要入库料箱' })
+      scanSuccess()
+    }
+  }).catch(err=>{
+    tips.value='料箱入库失败,请重新扫描工作站点'
+    scanStation.value=''
+    showNotify({ type: 'danger', duration: 3000, message:'料箱入库失败,请重新扫描工作站点' })
+    scanError()
+  }).finally(()=>{
+    closeLoading()
+  })
+}
+onUnmounted(() => {
+  closeListener()
+})
+// window.onRefresh = loadData
+</script>
+<style scoped lang="sass">
+.box-return
+  .box-return-content
+    .content-code
+      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
+
+
+</style>

+ 165 - 0
src/views/haikang/putaway/components/Box.vue

@@ -0,0 +1,165 @@
+<template>
+  <svg class="box-display" width="150" height="80" viewBox="0 0 300 160">
+    <g>
+      <rect x="0" y="80" width="300" height="80" />
+      <text x="10" y="135" font-family="Verdana" font-weight="bold" font-size="40" fill="green">
+        {{ box.name }}
+      </text>
+    </g>
+    <polygon class="line" points="0,80 50,0 250,0 300,80" />
+    <g v-if="box.category === 1">
+      <polygon class="single" points="0,80 50,1 250,1 300,80" />
+    </g>
+    <g v-if="box.category === 2">
+      <polygon class="line" points="0,80 50,1 150,1 150,80" />
+      <polygon class="line" points="150,0 150,80 300,80 250,0" />
+    </g>
+    <g v-if="box.category === 3">
+      <polygon class="line" points="0,80 50,1 120,1 100,80" />
+      <polygon class="line" points="100,80 120,1 180,1 200,80" />
+      <polygon class="line" points="200,80 180,1 250,1 300,80" />
+    </g>
+    <g v-if="box.category === 4">
+      <polygon class="line" points="29.17,33.33 50,0 150,0 150,33.33" />
+      <polygon class="line" points="150,33.33 150,0 250,0 270.83,33.33" />
+      <polygon class="line" points="0,80 29.17,33.33 150,33.33 150,80" />
+      <polygon class="line" points="150,33.33 150,80 300,80 270.83,33.33" />
+    </g>
+    <g v-if="box.category === 6">
+      <polygon class="line" points="29.17,33.33 50,0 117,0 110.39,33.33" />
+      <polygon class="line" points="117,0 110.39,33.33 191.61,33.33 185.5,0" />
+      <polygon class="line" points="191.61,33.33 185.5,0 250,0 270.83,33.33" />
+      <polygon class="line" points="200,80 191.61,33.33 270.83,33.33 300,80" />
+      <polygon class="line" points="110.39,33.33 100,80 200,80 191.61,33.33" />
+      <polygon class="line" points="0,80 29.17,33.33 110.39,33.33 100,80" />
+    </g>
+    <g v-if="box.category === 8">
+      <polygon class="line" points="29.17,33.33 50,0 100,0 93.39,33.33" />
+      <polygon class="line" points="100,0 93.39,33.33 150.61,33.33 152.5,0" />
+      <polygon class="line" points="150.61,33.33 152.5,0 205,0 210.83,33.33" />
+      <polygon class="line" points="205,33.33 200.83,0 250,0 270.83,33.33" />
+      <polygon class="line" points="210.83,80 205,33.33 270.83,33.33 300,80" />
+      <polygon class="line" points="148.5,80 150.61,33.33 205,33.33 210.83,80" />
+      <polygon class="line" points="93.39,33.33 85,80 148.5,80 150.61,33.33" />
+      <polygon class="line" points="0,80 29.17,33.33 93.39,33.33 85,80" />
+    </g>
+  </svg>
+</template>
+
+<script setup>
+import { ref, watch } from 'vue';
+
+// 接收父组件传递的数据
+const props = defineProps({
+  box: Object,
+});
+
+// 定义响应式变量
+const box = ref(props.box);
+
+// 监听 box.category 属性变化,更新 category
+watch(() => box.value.category, (newCategory) => {
+  resetCategory(newCategory);
+}, { immediate: true });
+
+// 设置分类并更新
+function resetCategory (category){
+  if (!category) {
+    category = 1;
+  } else {
+    category = Number(category);
+    if (category >= 0 && category <= 1) {
+      category = 1;
+    }
+    if (category === 5) {
+      category = 6;
+    }
+    if (category > 6) {
+      category = 8;
+    }
+  }
+  box.value.category = category;
+}
+
+// 高亮处理
+const clearHigh=()=> {
+  const elements = document.querySelectorAll('.successHigh, .exceptionHigh, .exception-text');
+  elements.forEach((element) => {
+    let className = element.getAttribute('class');
+    className = className.replace('successHigh', '').replace('exceptionHigh', '').trim();
+    element.setAttribute('class', className);
+    if (className.includes('exception-text')) {
+      element.remove();
+    }
+  });
+}
+
+const high=(index, isException)=> {
+  setTimeout(function () {
+    const element = document.getElementsByTagName('polygon')[index];
+    if (!element) return;
+
+    if (isException) {
+      element.setAttribute('class', element.getAttribute('class').replace('successHigh', '') + ' exceptionHigh');
+      const bbox = element.getBBox();
+      const textX = bbox.x + bbox.width / 2;
+      const textY = bbox.y + bbox.height / 2;
+
+      const textElement = document.createElementNS('http://www.w3.org/2000/svg', 'text');
+      textElement.setAttribute('class', 'exception-text');
+      textElement.setAttribute('x', textX);
+      textElement.setAttribute('y', textY);
+      textElement.setAttribute('data-index', index);
+      textElement.setAttribute('font-family', 'Verdana');
+      textElement.setAttribute('font-weight', 'bold');
+      textElement.setAttribute('font-size', '15');
+      textElement.setAttribute('text-anchor', 'middle');
+      textElement.setAttribute('dominant-baseline', 'central');
+      textElement.setAttribute('fill', 'red');
+      textElement.textContent = '异常';
+
+      element.parentNode.insertBefore(textElement, element.nextSibling);
+    } else {
+      if (element.getAttribute('class').includes('exceptionHigh')) {
+        element.setAttribute('class', element.getAttribute('class').replace('exceptionHigh', ''));
+        const textElements = element.parentNode.querySelectorAll(`.exception-text[data-index="${index}"]`);
+        textElements.forEach((textElement) => {
+          element.parentNode.removeChild(textElement);
+        });
+      }
+      element.setAttribute('class', element.getAttribute('class') + ' successHigh');
+    }
+  }, 50);
+}
+
+defineExpose({high,clearHigh})
+</script>
+
+<style scoped>
+g rect {
+  fill: #ffffff;
+  stroke-width: 3;
+  stroke: rgb(11, 51, 71);
+}
+.face {
+  fill: #ffffff;
+  stroke: rgb(11, 51, 71);
+  stroke-width: 3;
+}
+.line {
+  stroke: rgb(11, 51, 71);
+  stroke-width: 3;
+}
+.single {
+  fill: #ffffff;
+}
+.successHigh {
+  fill: RGB(103, 194, 58) !important;
+}
+.exceptionHigh {
+  fill: orange !important;
+}
+.exception-text {
+  pointer-events: none;
+}
+</style>

+ 96 - 0
src/views/haikang/putaway/components/GoBack.vue

@@ -0,0 +1,96 @@
+<template>
+  <div class="container-no-container">
+    <van-dialog v-model:show="goBackTrueFalseBy" :beforeClose="beforeClose" show-cancel-button>
+      <div style="margin: 10px 0">
+        <van-tabs v-model:active="active"  sieze="mini" @change="onTabs" >
+          <van-tab title="料箱回库" name="1">
+            <div v-if="barcodeActive.qty" style="font-size:14px;color:#666;padding-top: 10px">上架数量:{{count}},预计数量:{{barcodeActive.qty}}</div>
+            <div style="font-size: 14px;text-align: center;color: #333;padding: 10px">{{ workBinNo }},是否执行料箱回库?</div>
+          </van-tab>
+          <van-tab title="调取料箱并回库" name="2"  :disabled="Number(count)==Number(barcodeActive.qty)" >
+            <div v-if="barcodeActive.qty" style="font-size:14px;color:#666;padding-top: 10px">上架数量:{{count}},预计数量:{{barcodeActive.qty}}</div>
+            <van-cell style="text-align: left" >
+              <template #title><span>料箱类型:</span></template>
+              <template #label>
+                <van-radio-group v-model="bin"   direction="horizontal" style="justify-content: space-evenly">
+                  <van-radio name="HK-BOX-1" icon-size="18px" style="padding:5px 0" >全&nbsp;隔&nbsp;口</van-radio>
+                  <van-radio name="HK-BOX-2" icon-size="18px" style="padding:5px 0" >2分隔口</van-radio>
+                  <van-radio name="HK-BOX-3" icon-size="18px" style="padding:5px 0" >3分隔口</van-radio>
+                  <van-radio name="HK-BOX-4" icon-size="18px" style="padding:5px 0" >4分隔口</van-radio>
+                  <van-radio name="HK-BOX-6" icon-size="18px" style="padding:5px 0" >6分隔口</van-radio>
+                  <van-radio name="HK-BOX-8" icon-size="18px" style="padding:5px 0" >8分隔口</van-radio>
+                </van-radio-group>
+              </template>
+            </van-cell>
+            <van-cell style="text-align: left" title="是否空料箱"><template #right-icon><van-switch v-model="boxEmpty" size="18px" /></template></van-cell>
+            <van-field readonly :class="['code-input',boxCount>0?'success-border':'']" v-model="boxCount" ref="countRef" type="digit"
+                       label="料箱数量:" autocomplete="off" clearable :max="10000" placeholder="请输入料箱数量" />
+          </van-tab>
+        </van-tabs>
+      </div>
+    </van-dialog>
+  </div>
+</template>
+<script setup>
+import { ref } from 'vue'
+import { showToast } from 'vant'
+const goBackTrueFalseBy = ref(false)
+const boxCount = ref('1')
+const count = ref('')
+const countRef = ref(null)
+const active = ref('1')
+const workBinNo=ref('')
+const boxEmpty=ref(true)
+const bin=ref('HK-BOX-1')
+// 定义传入的 props
+const props = defineProps({
+  scanType: Number,
+})
+const barcodeActive=ref({})
+const show = async (code,type,number,item) => {
+  workBinNo.value=code
+  goBackTrueFalseBy.value = true
+  boxCount.value = '1'
+  count.value=number
+  active.value=type
+  barcodeActive.value=item
+}
+const onTabs=(e)=>{
+  if(e==2){
+    setTimeout(() => {
+      countRef.value?.focus()
+    }, 200)
+  }
+}
+const emit = defineEmits(['update:scanType', 'setGoBack'])
+const beforeClose = (action) =>
+  new Promise(async (resolve) => {
+    if (action === 'confirm') {
+      console.log(active.value)
+      if(active.value==2 && boxCount.value == ''){
+          showToast('请输入调取料箱数量')
+          return resolve(false)
+      }
+      emit('update:scanType', 1)
+      emit('setGoBack', {active:active.value,boxCount:boxCount.value,bin:bin.value,boxEmpty:boxEmpty.value})
+    }
+    emit('update:scanType', props.scanType)
+    resolve(true)
+  })
+defineExpose({ show })
+</script>
+
+<style scoped lang="sass">
+.container-no-container
+  .code-input
+    font-size: 16px
+    font-weight: bold
+    border-bottom: 2px solid #0077ff
+    margin-top: 10px
+    ::v-deep(.van-field__label)
+      width: unset
+      margin: 0
+  .success-border
+    border-bottom: 2px solid #1ca600
+
+</style>

+ 448 - 0
src/views/haikang/putaway/dispatch/index.vue

@@ -0,0 +1,448 @@
+<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>
+      <template #right>
+<!--        {{Object.keys(dataMap).length}}-->
+<!--        <div class="nav-right" @click="onClickRight">提交任务</div>-->
+      </template>
+    </van-nav-bar>
+    <div class="allocation">
+      <div class="code">
+        <div class="code-title">
+          <div><span style="font-size: 12px">容器:</span>{{ containerNo || '--' }}</div>
+          <div class="code-tips">
+            <van-notice-bar :background="'none'" :speed="50" :text="tips" />
+          </div>
+          <van-button plain size="mini" type="primary" @click="_setContainerNo()">切换容器</van-button>
+        </div>
+        <div class="code-input">
+          <van-search
+            v-model="wallNo"
+            placeholder="请扫描分拨墙号"
+            label="分拨墙号:"
+            @search="scanType=2"
+            left-icon=""
+            :class="[scanType===3?'search-input-barcode':'','van-hairline--bottom']"
+            @focus="scanType=3"
+            autocomplete="off"
+          >
+          </van-search>
+          <van-search
+            ref="searchRef"
+            v-model="searchBarcode"
+            placeholder="请扫描商品条码"
+            @search="_handlerScan(searchBarcode)"
+            label="商品条码:"
+            left-icon=""
+            :class="[scanType===2?'search-input-barcode':'','van-hairline--bottom']"
+            @focus="scanType=2"
+            autocomplete="off"
+          >
+          </van-search>
+          <van-search
+            ref="searchRef"
+            v-model="bin"
+            placeholder="分配格口"
+            label="分配格口:"
+            disabled
+            left-icon=""
+          >
+          </van-search>
+        </div>
+      </div>
+      <van-divider :style="{ color: '#333', borderColor: '#1989fa', padding: '0 16px',margin:'5px 0' }">上架库位
+      </van-divider>
+      <div class="move-stock-list">
+        <table class="task-table">
+          <thead>
+          <tr>
+            <th>库位</th>
+            <th>类型</th>
+            <th>数量</th>
+            <th style="width: 80px"></th>
+          </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>
+            <td>
+              <!--              <van-button type="primary" plain size="mini" style="width:100%" @click="setLocation(item)" v-if="!locationActive.location">选择</van-button>-->
+              <div>
+                <van-icon size="24" color="#07c160" name="success" />
+              </div>
+            </td>
+          </tr>
+          <tr v-else>
+            <td colspan="4">
+              <div>暂无数据</div>
+            </td>
+          </tr>
+          </tbody>
+        </table>
+      </div>
+    </div>
+    <!-- 条码输入组件 -->
+    <input-barcode :back="back" @setBarcode="setBarcode" ref="inputBarcodeRef" />
+    <!--  单据选择-->
+    <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">
+          <template #title>
+            {{ item.barcode }}({{ item.quantity }}件)
+          </template>
+          <template #label>
+            生产日期:{{ item.lotAtt01 || '--' }}-失效日期:{{ item.lotAtt02 || '--' }}
+          </template>
+        </van-cell>
+      </van-cell-group>
+    </van-action-sheet>
+  </div>
+</template>
+<script setup lang="ts">
+import { onMounted, onUnmounted, ref } from 'vue'
+import { showNotify, showToast } from 'vant'
+import { androidFocus, getHeader, goBack, playVoiceBin, scanError, scanSuccess } from '@/utils/android'
+import InputBarcode from '@/views/outbound/picking/components/InputBarcode.vue'
+import { closeListener, openListener, scanInit } from '@/utils/keydownListener'
+import { useStore } from '@/store/modules/user'
+import { getRecommendedLocation, getWaitPutawayList, setBindAllocateWall } from '@/api/haikang'
+import { barcodeToUpperCase } from '@/utils/dataType'
+import { closeLoading, showLoading } from '@/utils/loading'
+
+
+const store = useStore()
+try {
+  getHeader()
+  androidFocus()
+} catch (error) {
+}
+// 页面初始化
+onMounted(() => {
+  openListener()
+  scanInit(_handlerScan)
+  loadData()
+})
+const warehouse = store.warehouse
+//收货容器号
+const containerNo = ref('')
+//分拨墙号
+const wallNo = ref('')
+//扫描类型
+const scanType = ref(3)
+//条码
+const searchBarcode = ref('')
+// 错误提示
+const tips = ref('')
+//强制返回
+const back = ref(true)
+//输入框类型
+const inputBarcodeRef = ref(null)
+const inputBarcodeType = ref('barcode')
+const location=ref('')
+//库位类型
+const locationType = {
+  'EA': '件拣货库位',
+  'AP': '补充拣货位',
+  'CS': '箱拣货库位',
+  'HP': '快拣补货位',
+  'PC': '箱/件合并拣货库位',
+  'PT': '播种库位',
+  'RS': '存储库位',
+  'SS': '理货站',
+  'ST': '过渡库位',
+  'WB': '组装工作区',
+}
+// 格口数据
+const bin = ref('') //当前格口
+//推荐库位
+const locationList = ref([])
+const dataMap = ref({})
+
+// 设置容器号
+const setBarcode = (code) => {
+  if (inputBarcodeType.value === 'barcode') {
+    _handlerScan(code)
+    return
+  }
+  const params = { warehouse, container: code, page: 1, size: 1000, status: false }
+  getWaitPutawayList(params).then(res => {
+    if (res.data.records.length == 0) {
+      scanError()
+      inputBarcodeRef.value?.show('', '请扫描收货容器号', '暂未查询到待上架任务,请切换容器')
+    } else {
+      scanSuccess()
+      dataMap.value = groupedData(res.data.records)
+      scanType.value = 3
+      containerNo.value = code
+    }
+  }).catch(err => {
+    scanError()
+    inputBarcodeRef.value?.show('', '请扫描收货容器号', err.message)
+  })
+
+}
+//切换容器
+const _setContainerNo = () => {
+  inputBarcodeType.value = 'container'
+  back.value = false
+  inputBarcodeRef.value?.show('', '请扫描收货容器号', '')
+}
+//批次数据
+const lotBarcodeList = ref([])
+const lotBarcodeTrueFalseBy = ref(false)
+const barcodeActive = ref({})
+// 扫描条码监听
+const _handlerScan = (code) => {
+  if (code) {
+    if (scanType.value == 2) {
+      if (!wallNo.value) {
+        tips.value = `请先扫描分拨墙号`
+        showToast({ duration: 3000, message: '请先扫描分拨墙号' })
+        scanType.value = 3
+        searchBarcode.value = ''
+        bin.value = ''
+        locationActive.value = []
+        scanError()
+        return
+      }
+      scanSuccess()
+      searchBarcode.value = code
+      barcodeActive.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
+        }
+      } else {
+        scanError()
+        tips.value = `${code}-商品条码不匹配,请重新扫描`
+        showNotify({ type: 'danger', duration: 3000, message: `${code}-商品条码不匹配,请重新扫描` })
+        searchBarcode.value = ''
+        locationList.value = []
+      }
+    } else if (scanType.value == 3) {
+      wallNo.value = code
+      scanType.value = 2
+    }
+  }
+}
+//匹配待上架列表数据
+const matchingBarcodeItem = (data, barcode) => {
+  const matchingItems = []
+  for (const key in data) {
+    const barcodeList = key.match(/\((.*?)\)/)[1].split('、')
+    if (data.hasOwnProperty(key)) {
+      if (barcodeList.some(item => barcodeToUpperCase(item) === barcodeToUpperCase(barcode))) {
+        matchingItems.push(data[key])
+      }
+    }
+  }
+  return matchingItems.length > 0 ? matchingItems : []
+}
+// 获取库存数据
+const _getRecommendedLocation = async (lotNum, owner) => {
+  try {
+    const params = { warehouse, lotNum, owner,zoneGroup:'WH01-01' }
+    const res = await getRecommendedLocation(params)
+    locationList.value = res.data
+    //  'EA'数据
+    const eaItems = res.data.filter(item => item.type === 'EA')
+    // 获取 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
+      }
+      setLocation([result])
+    }
+  } catch (err) {
+    console.error(err)
+  }
+}
+// 设置库位
+const locationActive = ref([])
+const wallBinCounts = ref(new Map())
+const setLocation = (item) => {
+    locationActive.value = item
+    const data = {
+      warehouse,
+      equipment: wallNo.value,
+      container: containerNo.value,
+      barcode: barcodeActive.value.barcode,
+      barcodeAS: barcodeActive.value.barcodeAs,
+      sku: barcodeActive.value.sku,
+      location: locationActive.value[0].location,
+      lotNum: barcodeActive.value.lotNumber,
+    }
+    showLoading()
+    setBindAllocateWall(data).then(res => {
+      bin.value =res.data
+      tips.value = `请将${searchBarcode.value},放入分拨墙-${wallNo.value}-《${res.data}》格口`
+      playVoiceBin(Number(bin.value))
+      closeLoading()
+    }).catch(err => {
+      searchBarcode.value = ''
+      locationActive.value = []
+      tips.value = err.message
+      scanError()
+      closeLoading()
+    })
+}
+// 数据刷新
+const loadData = () => {
+  if (!containerNo.value) {
+    inputBarcodeType.value = 'container'
+    inputBarcodeRef.value?.show('', '请扫描收货容器号', '')
+    return
+  } else {
+    const params = { warehouse, container: containerNo.value, page: 1, size: 1000, status: false }
+    getWaitPutawayList(params).then(res => {
+      dataMap.value = groupedData(res.data.records)
+    })
+  }
+}
+//根据条码批次分组数据
+const groupedData = (data) => {
+  return data.reduce((acc, item) => {
+    const key = `(${item.barcode}、${item.barcodeAs}、${item.sku})-${item.lotNumber}`
+    if (acc[key]) {
+      acc[key].quantity += item.quantity
+    } else {
+      acc[key] = { ...item }
+    }
+    return acc
+  }, {})
+}
+
+onUnmounted(() => {
+  closeListener()
+})
+
+window.onRefresh = loadData
+
+//调用上架任务
+const onClickRight = () => {
+  console.log('right')
+}
+</script>
+<style scoped lang="sass">
+.container
+  background: #e9f4ff
+
+  .allocation
+    .code
+      box-sizing: border-box
+      padding: 8px 0
+
+      .code-title
+        display: flex
+        justify-content: space-between
+        padding: 0 15px 8px 15px
+
+      .code-input
+        ::v-deep(.van-search)
+          padding: 0
+
+        ::v-deep(.van-search__label)
+          font-size: 16px
+
+        ::v-deep(.van-search__field)
+          border-bottom: 2px solid #efefef
+          font-size: 16px
+
+        ::v-deep(.van-search__content)
+          background: #fff
+
+        .search-input-barcode
+          ::v-deep(.van-search__field)
+            border-bottom: 2px solid #0077ff
+            z-index: 2
+
+      .code-tips
+        color: #ed6a0c
+        flex: 1
+
+      .code-count
+        font-size: 16px
+        font-weight: bold
+
+        span
+          color: #0077ff
+
+    .location
+      background: #fff
+      text-align: left
+      padding: 10px 15px
+      margin-bottom: 10px
+      font-size: 14px
+
+    .move-stock-list
+      width: 100%
+      overflow-y: auto
+      max-height: 60vh
+      min-height: 100px
+
+      .move-button
+        background: #1989fa
+        color: #fff
+        width: 100%
+        height: 30px
+        font-size: 15px
+        line-height: 30px
+        font-weight: bold
+
+      .task-table, .task-table-bin, .task-table-box
+        width: 100%
+        table-layout: fixed
+        border-collapse: collapse
+        font-size: 15px
+
+      .task-table th, .task-table-bin th, .task-table td, .task-table-bin td, .task-table-box th, .task-table-box td
+        text-align: center
+        border: 1px solid #ccc
+        word-wrap: break-word
+        word-break: break-all
+
+      .task-table thead, .task-table-bin thead, .task-table-box thead
+        background-color: #3f8dff
+        position: sticky
+        top: 0
+        color: white
+        font-size: 15px
+
+      .task-table-bin thead
+        background-color: #3f8dff
+
+      .task-table-bin tbody
+        background: #cde7ff
+
+  .nav-right
+    padding: 14px 0 12px 5px
+    color: #fff
+
+
+</style>

+ 537 - 0
src/views/haikang/putaway/putaway/index.vue

@@ -0,0 +1,537 @@
+<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>
+      <template #right>
+        <div class="nav-right" @click="setPutaway(1)">料箱回库</div>
+      </template>
+    </van-nav-bar>
+    <div class="putaway">
+      <div class="putaway-top">
+        <div class="putaway-tips">
+          <div style="flex: 1"><van-notice-bar left-icon="volume-o">{{ tips }}</van-notice-bar></div>
+          <div class="putaway-tips-box" v-if="dataList.length>0">剩余料箱:{{ dataList[0].remainBoxCount || 0 }}</div>
+        </div>
+        <div class="putaway-input">
+          <div class="code-input">
+            <van-field v-model="workBinNo" placeholder="请扫描料箱号" label="料箱编号:" left-icon="" :class="[scanType===1?'search-input-barcode':'']"
+              autocomplete="off" readonly @click="setBarcodeInput(workBinNo,1)"></van-field>
+            <van-field v-model="searchBarcode" placeholder="请扫描商品条码" label="商品条码:" left-icon="" readonly :class="[scanType===2?'search-input-barcode':'']"
+              autocomplete="off" @click="setBarcodeInput(searchBarcode,2)"></van-field>
+            <van-field ref="countRef" v-model="count" type="number" placeholder="上架数量" label="上架数量:" left-icon="" autocomplete="off"
+                       :class="{'search-input-barcode': scanType === 3,'input-count': barcodeActive.qty}"  @keydown.enter="setPutaway(2)"
+                       :max="barcodeActive.qty?barcodeActive.qty:10000"
+            >
+              <template #button>
+                <div style="display: flex; align-items: center;flex-direction: column;margin-left: 20px;color:#333" v-if="barcodeActive.qty">
+                  <div style="height: 20px;font-size: 12px">预计</div>
+                  <div style="font-size: 16px;font-weight: bold">{{ barcodeActive.qty ||0 }}
+                  </div>
+                </div>
+              </template>
+            </van-field>
+            <van-field v-model="searchLocation" placeholder="请扫描库位" label="上架库位:" left-icon="" readonly :class="[scanType===4?'search-input-barcode':'']"
+                       autocomplete="off" @click="setBarcodeInput(searchLocation,4)"></van-field>
+          </div>
+        </div>
+        <div class="putaway-button">
+          <van-button type="primary" size="small" block  @click="setPutaway(2)" >提交上架</van-button>
+        </div>
+        <div class="putaway-box" v-if="barcodeActive.bin">
+          <div><box ref="boxRef" :box="{name:workBinNo,category:barcodeActive.gridCount}"></box></div>
+          <div  style="font-size: 14px;" v-if="barcodeActive.gridNum" >料箱格口:{{ barcodeActive.gridNum }}</div>
+          <div  style="font-size: 14px;"  v-else >料箱格口:请手动扫描</div>
+        </div>
+      </div>
+      <div class="putaway-bottom"  v-if="equipmentBarcodeList.length>0">
+        <div class="wall-list-box">
+          <div style="font-size: 14px">分拨墙-{{equipmentBarcodeList[0].equipment}}</div>
+          <div class="wall-list">
+            <div class="wall-item" v-for="(wall, wallIndex) in wallBinList" :key="wallIndex">
+              <div class="wall-item-sub" v-for="(bin, binIndex) in getRows(wall)" :key="binIndex">
+                <div class="wall-item-bin" v-for="item in bin">
+                  <div class="wall-item-bin-text">{{ item }}</div>
+                  <div class="wall-item-bin-high" :style="locationScanBarcodeBinList.includes(Number(item))?'background:#45d200':''" v-if="locationBarcodeBinList.includes(Number(item))">{{ item }}</div>
+                </div>
+              </div>
+            </div>
+          </div>
+        </div>
+      </div>
+    </div>
+    <input-barcode ref="inputBarcodeRef" @setBarcode="_handlerScan" />
+    <go-back ref="goBackRef"   v-model:scanType="scanType" @setGoBack="setGoBack"  />
+    <van-action-sheet v-model:show="equipmentTrueFalseBy" cancel-text="取消" description="请选择分拨墙" close-on-click-action>
+      <van-cell-group>
+        <van-cell v-for="(value,key) in equipmentMap" @click="selectEquipment(key)">
+          <template #title>
+           分拨墙:{{ key}}(容器:{{value[0].container}})
+          </template>
+        </van-cell>
+      </van-cell-group>
+    </van-action-sheet>
+  </div>
+</template>
+<script setup lang="ts">
+import { onMounted, onUnmounted, ref } from 'vue'
+import { getHeader, goBack, scanError, scanSuccess } from '@/utils/android'
+import { closeListener, openListener, scanInit } from '@/utils/keydownListener'
+import { useStore } from '@/store/modules/user'
+import { showNotify } from 'vant'
+import { barcodeToUpperCase, toMap } from '@/utils/dataType'
+import InputBarcode from '@/views/outbound/picking/components/InputBarcode.vue'
+import Box from '@/views/haikang/putaway/components/Box.vue'
+import GoBack from '@/views/haikang/putaway/components/GoBack.vue'
+import { boxReturn, getShelveItemInfo, outboundEmptyBoxAndBindTask, setBoxInboundInventory } from '@/api/haikang'
+import { closeLoading, showLoading } from '@/utils/loading'
+const store = useStore()
+const warehouse = store.warehouse
+try {
+  getHeader()
+} catch (error) {
+}
+// 页面初始化
+onMounted(() => {
+  openListener()
+  scanInit(_handlerScan)
+  loadData()
+})
+
+const dataList=ref([])
+
+//料箱编号
+const workBinNo = ref('')
+//扫描类型
+const scanType = ref(1) //料箱1、商品条码2,站台3
+//提示
+const tips = ref('请扫描料箱编号')
+//匹配库位条码
+const matchedBarcodeItem=ref([])
+//条码
+const searchBarcode = ref('')
+//上架数量
+const count = ref('')
+const countRef=ref(null)
+//上架库位
+const searchLocation=ref('')
+const locationList = (data) => {
+  return data.reduce((acc, item) => {
+    const key = item.boxCode
+    acc[key] = acc[key] || []
+    acc[key].push(item)
+    return acc
+  }, {})
+}
+//料箱库位
+const locationMap = ref({})
+const wallBinList = ref([
+  ['1', '2', '3', '4', '5', '6', '7', '8', '9', '10', '11', '12', '13', '14', '15', '16', '17', '18', '19', '20'],
+  ['21', '22', '23', '24', '25', '26', '27', '28', '29', '30', '31', '32', '33', '34', '35', '36', '37', '38', '39', '40'],
+  ['41', '42', '43', '44', '45', '46', '47', '48', '49', '50', '51', '52', '53', '54', '55', '56', '57', '58', '59', '60'],
+])
+const getRows = (wall) => {
+  let rows = []
+  for (let i = 0; i < wall.length; i += 4) {
+    rows.push(wall.slice(i, i + 4))
+  }
+  return rows.reverse()
+}
+//料箱内商品
+const locationDetailList = ref([])
+// //当前扫描商品
+const barcodeActive = ref({})
+//分拨墙是否展示
+const equipmentTrueFalseBy=ref(false)
+// 分拨墙map
+const equipmentMap=ref({})
+//分拨墙条码列表
+const equipmentBarcodeList=ref([])
+//料箱内已扫描条码
+const locationScanBarcodeBinList = ref([])
+//料箱内商品所有格口
+const locationBarcodeBinList = ref([])
+const boxRef = ref(null)
+const _handlerScan = (code) => {
+  if (scanType.value == 1) {
+    workBinNo.value = code
+    showLoading()
+    getShelveItemInfo({warehouse, boxCode: code, }).then(res => {
+      if(res.data.length>0){
+        reset()
+        dataList.value=res.data
+        locationMap.value = locationList(res.data)
+        locationDetailList.value = locationMap.value[barcodeToUpperCase(code)]
+        equipmentMap.value=locationDetailList.value.reduce((acc, item) => {
+          if (!acc[item.equipment]) {
+            acc[item.equipment] = [];
+          }
+          acc[item.equipment].push(item);
+          return acc;
+        }, {});
+        const keys = Object.keys(equipmentMap.value);
+        if (keys.length==1) {
+          equipmentBarcodeList.value = equipmentMap.value[keys[0]]
+          equipmentBarcodeList.value.forEach((item) => {
+            locationBarcodeBinList.value.push(item.bin)
+          })
+          locationBarcodeBinList.value = [...new Set(locationBarcodeBinList.value)]
+        } else {
+          equipmentTrueFalseBy.value=true
+        }
+        scanType.value = 2
+        tips.value = `请扫描商品条码`
+        scanSuccess()
+      }else{
+        scanError()
+        tips.value = `${workBinNo.value},待上架任务已取消`
+        showNotify({ type: 'danger', duration: 3000, message: `${workBinNo.value},待上架任务已取消` })
+        workBinNo.value=''
+      }
+      closeLoading()
+    }).catch(err=>{
+      reset()
+      searchBarcode.value = ''
+      count.value=''
+      searchLocation.value=''
+      tips.value = err.message
+      barcodeActive.value={}
+      showNotify({ type: 'danger', duration: 3000, message:  err.message })
+      scanError()
+      closeLoading()
+    })
+  } else if (scanType.value == 2) {
+    matchedBarcodeItem.value = equipmentBarcodeList.value.filter(item =>
+      barcodeToUpperCase(item.barcode)== barcodeToUpperCase(code)|| barcodeToUpperCase(item.sku)== barcodeToUpperCase(code)||
+      item.barcodeAs== barcodeToUpperCase(code)
+    )
+    if (matchedBarcodeItem.value.length>0) {
+      searchBarcode.value = code
+      matchedBarcodeItem.value.forEach((item) => {
+          locationScanBarcodeBinList.value.push(item.bin)
+        })
+        locationScanBarcodeBinList.value = [...new Set(locationScanBarcodeBinList.value)]
+        barcodeActive.value =matchedBarcodeItem.value[0]
+        searchLocation.value=barcodeActive.value.locationId
+        setTimeout(() => {
+          boxRef.value?.clearHigh()
+          boxRef.value?.high(barcodeActive.value.gridNum || 1)
+        }, 300)
+        scanType.value = 3
+        count.value=1
+        countRef.value?.focus()
+        tips.value = `请扫输入上架数量`
+      scanError()
+    } else {
+      count.value=''
+      searchBarcode.value = ''
+      searchLocation.value=''
+      barcodeActive.value={}
+      tips.value = `${code}-商品条码不匹配,请重新扫描`
+      showNotify({ type: 'danger', duration: 3000, message: `${code}-商品条码不匹配,请重新扫描` })
+      scanError()
+    }
+  }else if(scanType.value==4){
+    searchLocation.value = code
+  }
+}
+
+// 选择分拨墙
+const selectEquipment=(key)=>{
+  equipmentBarcodeList.value = equipmentMap.value[key]
+  equipmentTrueFalseBy.value=false
+  equipmentBarcodeList.value.forEach((item) => {
+    locationBarcodeBinList.value.push(item.bin)
+  })
+  locationBarcodeBinList.value = [...new Set(locationBarcodeBinList.value)]
+
+}
+const reset=()=>{
+  count.value=''
+  equipmentBarcodeList.value=[]
+  locationBarcodeBinList.value=[]
+  locationScanBarcodeBinList.value=[]
+  equipmentMap.value={}
+  dataList.value=[]
+}
+const inputCheck=()=>{
+  if(!workBinNo.value){
+    scanType.value = 1
+    tips.value = `请扫描料箱编号`
+    showNotify({ type: 'danger', duration: 3000, message: `请扫描料箱编号` })
+    scanError()
+    return false
+  }
+  if(!searchBarcode.value){
+    scanType.value = 2
+    tips.value = `请扫描商品条码`
+    showNotify({ type: 'danger', duration: 3000, message: `请扫描商品条码` })
+    scanError()
+    return false
+  }
+  if(!count.value){
+    scanType.value = 3
+    tips.value = `请输入上架数量`
+    showNotify({ type: 'danger', duration: 3000, message: `请扫输入上架数量` })
+    countRef.value?.focus()
+    scanError()
+    return false
+  }
+  if(!searchLocation.value){
+    scanType.value = 4
+    tips.value = `请扫描上架库位`
+    showNotify({ type: 'danger', duration: 3000, message: `请扫描上架库位` })
+    scanError()
+    return false
+  }
+  if(Number(count.value)>Number(barcodeActive.qty)){
+    scanType.value = 3
+    tips.value = `请输入上架数量`
+    scanError()
+    countRef.value?.focus()
+    showNotify({ type: 'danger', duration: 3000, message: `上架数量不能大于预计上架数量` })
+    return false
+  }
+  return true
+}
+const goBackRef=ref(null)
+const setPutaway=async (type)=>{
+  if(type==2){
+    if(!inputCheck()) return
+    //料箱需要分拨墙格口和扫描格口不一致
+    if(locationBarcodeBinList.value.length!=locationScanBarcodeBinList.value.length){
+     const res= await _setBoxInboundInventory()
+      refreshPutawayList(barcodeActive.value)
+      if(res){
+        barcodeActive.value=''
+        searchBarcode.value=''
+        searchLocation.value=''
+        count.value=''
+        scanType.value = 2
+        tips.value = `请继续扫描商品条码`
+        scanSuccess()
+        showNotify({ type: 'success', duration: 3000, message: `请继续扫描商品条码` })
+      }
+      return
+    }
+    let activeType='1'
+    if(locationBarcodeBinList.value.length==1 && count.value!=barcodeActive.value.qty){
+      activeType='2'
+    }
+    goBackRef.value?.show(workBinNo.value,activeType,count.value,barcodeActive.value)
+  }else if(type==1){
+    if(!barcodeActive.value.container){
+      scanType.value = 1
+      tips.value = `请先扫描商品条码,查询待上架信息`
+      showNotify({ type: 'danger', duration: 3000, message: `请先扫描商品条码,查询待上架信息` })
+      scanError()
+      return false
+    }
+    goBackRef.value?.show(workBinNo.value,'1','', {})
+  }
+}
+const setGoBack=async (item)=>{
+  console.log(item,'回库')
+  const res= await _setBoxInboundInventory()
+  if(res){
+    if(item.active==1){
+      const {warehouse,container,boxCode}=barcodeActive.value
+      const boxRes= await boxReturn({warehouse,container,boxCode})
+      if(boxRes){
+        reset()
+        barcodeActive.value={}
+        workBinNo.value=''
+        searchBarcode.value=''
+        searchLocation.value=''
+        scanType.value = 1
+        tips.value = `请扫描料箱编号`
+        showNotify({ type: 'success', duration: 3000, message: `请扫描下一个料箱编号` })
+        scanSuccess()
+      }
+    }else if(item.active==2){
+      const {warehouse,container,boxCode,lotNum}=barcodeActive.value
+      const boxRes= await outboundEmptyBoxAndBindTask({warehouse,container,originalBoxCode:boxCode,lotNum,boxType:item.bin,boxEmpty:item.boxEmpty}).catch((err=>{
+        reset()
+        barcodeActive.value={}
+        workBinNo.value=''
+        searchBarcode.value=''
+        searchLocation.value=''
+        scanType.value = 1
+        tips.value = `请扫描料箱编号`
+        scanError()
+      }))
+      if(boxRes){
+        reset()
+        barcodeActive.value={}
+        workBinNo.value=''
+        searchBarcode.value=''
+        searchLocation.value=''
+        scanType.value = 1
+        tips.value = `料箱调取成功,请继续扫描料箱编号`
+        showNotify({ type: 'success', duration: 3000, message: `料箱调取成功,请继续扫描料箱编号` })
+        scanSuccess()
+      }
+    }
+  }
+}
+// 上架
+const _setBoxInboundInventory = async () => {
+  try {
+    console.log(barcodeActive.value)
+    const {container,sku,boxCode,taskLineNoList,taskNo,warehouse,lotNum}=barcodeActive.value
+    const data={
+      container,sku,boxCode,taskLineNoList,taskNo,warehouse,lotNum,
+      location:searchLocation.value,
+      quantity:count.value
+    }
+    const res = await setBoxInboundInventory(data)
+    return res
+  } catch (error) {
+    scanError()
+    console.error('上架操作失败:', error);
+    return null
+  }
+};
+
+//设置条码
+const inputBarcodeRef = ref(null)
+const setBarcodeInput = (code, type) => {
+  const typeMap = { 1: '请扫描料箱编号', 2: '请扫商品条码', 3: '请扫站台编号', 4: '请扫上架库位' }
+  scanType.value = type
+  inputBarcodeRef.value?.show(code, typeMap[type])
+}
+// 数据刷新
+const loadData = () => {
+  // locationMap.value = locationList(result.value.items)
+}
+// 刷新待上架数据
+const refreshPutawayList = (item) => {
+  getShelveItemInfo({warehouse:item.warehouse, boxCode:item.boxCode,}).then(res => {
+    if(res.data.length>0) {
+      dataList.value = res.data
+      locationMap.value = locationList(res.data)
+      locationDetailList.value = locationMap.value[barcodeToUpperCase(item.boxCode)]
+      equipmentMap.value=locationDetailList.value.reduce((acc, item) => {
+        if (!acc[item.equipment]) {
+          acc[item.equipment] = [];
+        }
+        acc[item.equipment].push(item);
+        return acc;
+      }, {})
+      equipmentBarcodeList.value = equipmentMap.value[item.equipment]
+    }
+  })
+}
+onUnmounted(() => {
+  closeListener()
+})
+
+window.onRefresh = loadData
+</script>
+<style scoped lang="sass">
+.container
+  background: #e9f4ff
+
+  .putaway
+    display: flex
+    flex-direction: column
+    height: calc(100vh - 46px)
+    justify-content: space-between
+    .putaway-tips
+      display: flex
+      justify-content: space-between
+      .putaway-tips-box
+        padding-right: 10px
+        background: #fffbe8
+        color: #333
+        font-size: 14px
+        font-weight: bold
+    .putaway-input
+      .code-input
+        ::v-deep(.van-cell)
+          padding: 5px 20px 0 20px
+
+        ::v-deep(.van-field__control)
+          border-bottom: 2px solid #efefef
+          font-size: 16px
+
+        ::v-deep(.van-field__label)
+          width: unset
+          font-size: 16px
+
+        .search-input-barcode
+          ::v-deep(.van-field__control)
+            border-bottom: 2px solid #0077ff
+            z-index: 2
+        .input-count
+          ::v-deep(.van-field__control)
+            line-height: 43px
+
+
+    .putaway-button
+      padding: 10px 20px
+
+    .wall-list-box
+      background: #646566
+      color: #fff
+      font-size: 14px
+      font-weight: bold
+      //position: fixed
+      bottom: 0
+      left: 0
+      z-index: 9
+      width: 100%
+
+      .wall-list
+        background: #c8c9cc
+        text-align: left
+        font-size: 14px
+        display: flex
+        gap: 5px
+
+        .wall-item
+          flex: 1
+          gap: 2px
+          display: flex
+          flex-direction: column
+
+          .wall-item-sub
+            display: flex
+            gap: 2px
+
+            .wall-item-bin
+              flex: 1
+              display: flex
+              background: #fff
+              align-items: center
+              justify-content: center
+              padding: 15px 0
+              font-size: 14px
+              color: #333
+              position: relative
+              //.wall-item-bin-text
+              .wall-item-bin-high
+                position: absolute
+                height: 100%
+                width: 100%
+                background: #ff8d29
+                font-size: 18px
+                font-weight: bold
+                display: flex
+                align-items: center
+                justify-content: center
+                animation: scaleAnimation 3s infinite
+                @keyframes scaleAnimation
+                  0%
+                    transform: scale(0.8)
+                  50%
+                    transform: scale(1)
+                  100%
+                    transform: scale(0.8)
+
+  .nav-right
+    padding: 14px 0 12px 5px
+    color: #fff
+
+</style>

+ 9 - 6
src/views/index.vue

@@ -2,12 +2,15 @@
   <div class="container">
   <div class="container">
     <van-image class="image" :src="imageUrl" ></van-image>
     <van-image class="image" :src="imageUrl" ></van-image>
     <div class="name" >{{userInfo.username}}</div>
     <div class="name" >{{userInfo.username}}</div>
-    <div class="home" @click="onRouter('picking')">进入拣货</div>
-    <div class="home" @click="onRouter('picking-aisle')">进入巷道拣货</div>
-    <div class="home" @click="onRouter('blind-receiving')">进入盲扫</div>
-    <div class="home" @click="onRouter('check-move-stock')">进入反拣还库</div>
-    <div class="home" @click="onRouter('piece-dashboard')">进入计件面板</div>
-    <div class="home" @click="onRouter('take-delivery')">进入收货</div>
+    <div class="home" @click="onRouter('picking')">拣货</div>
+<!--    <div class="home" @click="onRouter('picking-aisle')">巷道拣货</div>-->
+    <div class="home" @click="onRouter('blind-receiving')">盲扫</div>
+<!--    <div class="home" @click="onRouter('check-move-stock')">反拣还库</div>-->
+    <div class="home" @click="onRouter('piece-dashboard')">计件面板</div>
+    <div class="home" @click="onRouter('take-delivery')">收货</div>
+    <div class="home" @click="onRouter('hik-putaway-allocation')">海康上架-调度</div>
+    <div class="home" @click="onRouter('hik-putaway')">海康上架</div>
+    <div class="home" @click="onRouter('hik-box-return')">海康-入库</div>
   </div>
   </div>
 </template>
 </template>
 <script setup>
 <script setup>