|
|
@@ -0,0 +1,738 @@
|
|
|
+<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="onClickRight">提交任务</div>-->
|
|
|
+ <!-- </template>-->
|
|
|
+ </van-nav-bar>
|
|
|
+ <div class="large">
|
|
|
+ <div class="large-title">
|
|
|
+ <!-- <div><span style="font-size: 12px">订单号:</span>{{ orderNo || '--' }}</div>-->
|
|
|
+ <div class="large-tips">
|
|
|
+ <van-notice-bar :background="'none'" :speed="50" :text="tips" />
|
|
|
+ </div>
|
|
|
+ <van-button plain size="mini" type="primary" @click="_setOrderNo()">更换订单/快递</van-button>
|
|
|
+ </div>
|
|
|
+ <div class="scan-barcode">
|
|
|
+ <van-field v-model.lazy="scanBarcode" label-align="left" placeholder="请扫描商品条码/SKU" label="商品条码:"
|
|
|
+ ref="barcodeNumberRef" class="input-barcode" autocomplete="off" @keydown.enter="_handlerScan(scanBarcode)" />
|
|
|
+ </div>
|
|
|
+ <div class="order-detail">
|
|
|
+ <div class="picking-no">
|
|
|
+ <div class="picking-code">
|
|
|
+ <van-icon name="stop-circle-o" color="#419bff" />
|
|
|
+ <span style="padding-left: 5px">单号:{{ orderDetail.orderNo }}</span></div>
|
|
|
+ <div>{{ orderDetail.carrierName || '--' }}</div>
|
|
|
+ </div>
|
|
|
+ <div class="picking-container ">
|
|
|
+ <div style="display: flex;padding-top: 5px" @click="setPrinter()">
|
|
|
+ <div>打印机:</div>
|
|
|
+ <div v-if="printer">{{printer.printer}}</div>
|
|
|
+ <div style="text-decoration: underline;color: #0077ff">设置打印机<van-icon name="edit" color="#0077ff"/> </div>
|
|
|
+ </div>
|
|
|
+ <div class="picking-order-count ">
|
|
|
+ <div>产品数量:
|
|
|
+ <span>{{scanOrderBarcodeCount}}/{{ orderBarcodeCount }}</span>
|
|
|
+ </div>
|
|
|
+ <div>耗材数量:
|
|
|
+ <span>{{ scanMaterialCount }}/{{ materialCount }}</span>
|
|
|
+ </div>
|
|
|
+ <div>已装箱数:
|
|
|
+ <span v-if="orderDetail.orderPacking && orderDetail.orderPacking.length>0" style="text-decoration: underline;color: #0077ff" @click="resetPacking" >{{ orderDetail.orderPacking.length }}<van-icon name="arrow-double-right" color="#0077ff" /></span>
|
|
|
+ <span v-else>0</span>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <div class="picking-button">
|
|
|
+ <div class="picking-button-item" @click="reset()">重置</div>
|
|
|
+ <div class="picking-button-item" @click="print('A3001_SO_PACKINGLIST',orderDetail.orderNo)">总清单</div>
|
|
|
+ <div class="picking-button-item" @click="setPacking('batch')">批量分箱</div>
|
|
|
+ <div class="picking-button-item" @click="setPacking('single')">装箱</div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <div class="order-list-box">
|
|
|
+ <van-divider style="margin: 0;padding: 5px 15px">
|
|
|
+ <template #default>
|
|
|
+ <div style="display: flex;align-items: center">订单明细(<div style="background: #E6A23C;height: 10px;width: 10px;margin:0 5px"></div><div>待装箱商品)</div></div>
|
|
|
+ </template>
|
|
|
+ </van-divider>
|
|
|
+ <div class="order-list">
|
|
|
+ <table class="task-table">
|
|
|
+ <thead>
|
|
|
+ <tr>
|
|
|
+ <th style="width: 20px">#</th>
|
|
|
+ <th style="width: 40%">商品条码</th>
|
|
|
+ <th>数量</th>
|
|
|
+ <th>剩余</th>
|
|
|
+ <th>状态</th>
|
|
|
+ <th v-if="isUniqueCode">标记</th>
|
|
|
+ </tr>
|
|
|
+ </thead>
|
|
|
+ <tbody>
|
|
|
+ <tr v-for="(item, index) in orderList" :key="index" v-if="orderList.length>0" :style="rowStyle(item)" >
|
|
|
+ <td>{{ index + 1 }}</td>
|
|
|
+ <td>{{ item.barcode }} <van-tag type="success" v-if="item.universalCode">万用</van-tag></td>
|
|
|
+ <td>
|
|
|
+ <span v-if="item.qtyOrdered" :style="item.qty!=item.oldQuantity && item.oldQuantity!=0 && item.qty!=0?'color:#b40a1e':''">{{ item.qty }}/{{ item.qtyOrdered }}</span>
|
|
|
+ <span v-else><van-tag type="warning">耗材</van-tag></span>
|
|
|
+ </td>
|
|
|
+ <td>{{ item.qty }}</td>
|
|
|
+ <td>{{ statusMap[item.status] || '' }}</td>
|
|
|
+ <td v-if="isUniqueCode">
|
|
|
+ <van-tag v-if="item.uniqueRegExp" type="warning">唯一码</van-tag>
|
|
|
+ <van-tag v-if="item.imeiRegExp" type="primary">IMEI码</van-tag>
|
|
|
+ </td>
|
|
|
+ </tr>
|
|
|
+ <tr v-else>
|
|
|
+ <td colspan="5">
|
|
|
+ <div>暂无数据</div>
|
|
|
+ </td>
|
|
|
+ </tr>
|
|
|
+ </tbody>
|
|
|
+ </table>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <!-- 条码输入组件 -->
|
|
|
+ <input-barcode :back="back" @setBarcode="setBarcode" ref="inputBarcodeRef" />
|
|
|
+ <!-- 打印面单-->
|
|
|
+ <printer ref="printerRef" @onPrint="onPrint" />
|
|
|
+ <!-- 批量扫描-->
|
|
|
+ <van-dialog v-model:show="barcodeNumberTrueFalseBy" title="批量扫描" show-cancel-button :beforeClose="beforeClose" :keyboardEnabled="false" >
|
|
|
+ <van-field v-model="barcodeNumber" autocomplete="off" center border label="数量:" placeholder="请输入数量"
|
|
|
+ type="digit" name="pattern" ref="barcodeNumberRef" class="count-input" @keydown.enter="onSubmitCount"
|
|
|
+ label-width="70px" label-align="center" :rules="[{ pattern, message: '请输入正确数量' }]">
|
|
|
+ </van-field>
|
|
|
+ <van-row :gutter="[5, 5]" style="margin: 10px 20px;font-size: 14px;text-align: left;color:#333" v-for="item in matchBarcodeList">
|
|
|
+ <van-col span="12">条码:{{item.barcode}}</van-col>
|
|
|
+ <van-col span="12">数量:{{item.qty}}</van-col>
|
|
|
+ </van-row>
|
|
|
+ </van-dialog>
|
|
|
+ <!-- 装箱-->
|
|
|
+ <check-packing ref="checkPackingRef" @cancelOrder="cancelOrder" @resetPackingStatus="resetPackingStatus" @print="print"/>
|
|
|
+ <!-- 批量装箱-->
|
|
|
+ <batch-packing ref="batchPackingRef" @print="print" @loadData="loadData" />
|
|
|
+ <!-- 重置装箱-->
|
|
|
+ <packing-list ref="packingListRef" @loadData="loadData" />
|
|
|
+ </div>
|
|
|
+</template>
|
|
|
+<script setup >
|
|
|
+import { onMounted, onUnmounted, computed, ref } from 'vue'
|
|
|
+import { androidFocus, getHeader, goBack, scanError, scanSuccess } from '@/utils/android'
|
|
|
+import { closeListener, openListener, scanInit } from '@/utils/keydownListener'
|
|
|
+import InputBarcode from '@/views/outbound/picking/components/InputBarcode.vue'
|
|
|
+import { useStore } from '@/store/modules/user'
|
|
|
+import { closeLoading, showLoading } from '@/utils/loading'
|
|
|
+import { getPendingReviewTask, reversePicking } from '@/api/check'
|
|
|
+import { barcodeToUpperCase } from '@/utils/dataType'
|
|
|
+import { showConfirmDialog, showDialog, showNotify, showToast } from 'vant'
|
|
|
+import { fluxPrint } from '@/api/picking'
|
|
|
+import Printer from '@/components/Printer.vue'
|
|
|
+import CheckPacking from '@/views/outbound/check/components/CheckPacking.vue'
|
|
|
+import BatchPacking from '@/views/outbound/check/components/BatchPacking.vue'
|
|
|
+import PackingList from '@/views/outbound/check/components/PackingList.vue'
|
|
|
+// 设置波次号
|
|
|
+const store = useStore()
|
|
|
+try {
|
|
|
+ getHeader()
|
|
|
+ androidFocus()
|
|
|
+} catch (error) {
|
|
|
+}
|
|
|
+// 页面初始化
|
|
|
+onMounted(() => {
|
|
|
+ openListener()
|
|
|
+ scanInit(_handlerScan)
|
|
|
+ loadData()
|
|
|
+})
|
|
|
+const warehouse = store.warehouse
|
|
|
+//SOZ25070900018
|
|
|
+const orderNo = ref('')
|
|
|
+// 错误提示
|
|
|
+const tips = ref('请扫描订单/快递单号')
|
|
|
+//强制返回
|
|
|
+const back = ref(true)
|
|
|
+const scanBarcode = ref('')
|
|
|
+const inputBarcodeRef = ref(null)
|
|
|
+// 订单明细
|
|
|
+const orderDetail = ref({})
|
|
|
+const isUniqueCode = ref(false)
|
|
|
+const statusMap = {
|
|
|
+ '00': '创建',
|
|
|
+ '20': '预配',
|
|
|
+ '30': '部分分配',
|
|
|
+ '40': '已分配',
|
|
|
+ '50': '待拣货',
|
|
|
+ '60': '已拣货',
|
|
|
+ '61': '分拣完成',
|
|
|
+ '90': '订单取消',
|
|
|
+}
|
|
|
+//订单列表
|
|
|
+const dataList = ref([])
|
|
|
+const orderList = computed(() => {
|
|
|
+ return dataList.value
|
|
|
+ .filter(item => item.qty !== 0 || item.isPacking)
|
|
|
+ .sort((a, b) => {
|
|
|
+ const statusPriority = {
|
|
|
+ '60': 0,
|
|
|
+ '600': 1,
|
|
|
+ '50': 2,
|
|
|
+ '40': 3,
|
|
|
+ '30': 4,
|
|
|
+ '20': 5,
|
|
|
+ '00': 6,
|
|
|
+ }
|
|
|
+ if (statusPriority[a.status] !== statusPriority[b.status]) {
|
|
|
+ return statusPriority[a.status] - statusPriority[b.status]
|
|
|
+ }
|
|
|
+ return 0
|
|
|
+ })
|
|
|
+})
|
|
|
+//订单产品总数
|
|
|
+const orderBarcodeCount = computed(() => {
|
|
|
+ return dataList.value.reduce((sum, item) => {
|
|
|
+ if (item.qtyOrdered != null) {
|
|
|
+ return sum + Number(item.oldQty)
|
|
|
+ }
|
|
|
+ return sum
|
|
|
+ }, 0)
|
|
|
+})
|
|
|
+//扫描订单产品总数
|
|
|
+const scanOrderBarcodeCount = computed(() => {
|
|
|
+ return dataList.value.reduce((sum, item) => {
|
|
|
+ if (item.qtyOrdered != null) {
|
|
|
+ return sum + Number(item.oldQuantity)
|
|
|
+ }
|
|
|
+ return sum
|
|
|
+ }, 0)
|
|
|
+})
|
|
|
+//耗材总数
|
|
|
+const materialCount = computed(() => {
|
|
|
+ return dataList.value.reduce((sum, item) => {
|
|
|
+ if (item.qtyOrdered == null) {
|
|
|
+ return sum + Number(item.oldQty)
|
|
|
+ }
|
|
|
+ return sum
|
|
|
+ }, 0)
|
|
|
+})
|
|
|
+const scanMaterialCount = computed(() => {
|
|
|
+ return dataList.value.reduce((sum, item) => {
|
|
|
+ if (item.qtyOrdered == null) {
|
|
|
+ return sum + Number(item.quantity)
|
|
|
+ }
|
|
|
+ return sum
|
|
|
+ }, 0)
|
|
|
+})
|
|
|
+
|
|
|
+//匹配条码
|
|
|
+const matchBarcodeList = ref([])
|
|
|
+//扣除数量
|
|
|
+const barcodeNumberTrueFalseBy = ref(false)
|
|
|
+const barcodeNumberRef = ref(null)
|
|
|
+const barcodeNumber=ref('')
|
|
|
+const pattern=/^[0-9]\d*$/
|
|
|
+const _handlerScan = async (code) => {
|
|
|
+ if (code) {
|
|
|
+ if (isUniqueCode.value) {
|
|
|
+ scanError()
|
|
|
+ scanBarcode.value = ''
|
|
|
+ showNotify({ type: 'warning', duration: 3000, message: `此单包含唯一码/IMEI码,请到PC复核` })
|
|
|
+ return
|
|
|
+ }
|
|
|
+ const barcode = [...new Set(
|
|
|
+ orderList.value
|
|
|
+ .filter(item => (item.status == '60' || item.status == '600'))
|
|
|
+ .flatMap(item => [item.barcode, item.barcode2, item.sku, item.universalCode])
|
|
|
+ .filter(value => value !== null && value !== '' && value !== undefined),
|
|
|
+ )]
|
|
|
+ const checkBarcode = barcodeToUpperCase(code)
|
|
|
+ if (barcode.some(item => barcodeToUpperCase(item) === checkBarcode)) {
|
|
|
+ dataList.value = await barcodeMatching(checkBarcode)
|
|
|
+ matchBarcodeList.value = dataList.value.filter(item => (item.barcode === checkBarcode || item.sku === checkBarcode || item.barcode2 === checkBarcode || item.universalCode == checkBarcode) && (item.status == '60' || item.status == '600') && item.qty > 0)
|
|
|
+ if (matchBarcodeList.value.length > 0) {
|
|
|
+ scanBarcode.value = code
|
|
|
+ const allCount = matchBarcodeList.value.reduce((sum, item) => sum + Number(item.qty), 0)
|
|
|
+ if (allCount > 1) {
|
|
|
+ barcodeNumberTrueFalseBy.value = true
|
|
|
+ setTimeout(() => {
|
|
|
+ barcodeNumber.value=''
|
|
|
+ barcodeNumberRef.value?.focus()
|
|
|
+ },300)
|
|
|
+ return
|
|
|
+ }
|
|
|
+ cutBarcode([matchBarcodeList.value[0]], 1)
|
|
|
+ } else {
|
|
|
+ scanBarcode.value = ''
|
|
|
+ scanError()
|
|
|
+ tips.value = `商品条码${code},已全部扫描完成`
|
|
|
+ showNotify({ type: 'warning', duration: 3000, message: `商品条码${code},已全部扫描完成` })
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ scanBarcode.value = ''
|
|
|
+ tips.value = `商品条码${code},不匹配请重新扫描!`
|
|
|
+ showNotify({ type: 'warning', duration: 3000, message: `商品条码${code},不匹配请重新扫描!` })
|
|
|
+ scanError()
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+const onSubmitCount=()=>{
|
|
|
+ if(!barcodeNumber.value){
|
|
|
+ tips.value='请输入数量'
|
|
|
+ showToast({duration:5000,message:'请输入数量'})
|
|
|
+ return
|
|
|
+ }
|
|
|
+ const allCount = matchBarcodeList.value.reduce((sum, item) => sum + Number(item.qty), 0)
|
|
|
+ if(Number(barcodeNumber.value)>allCount){
|
|
|
+ const message='数量不能大于最大数量'+allCount
|
|
|
+ tips.value=message
|
|
|
+ showToast({duration:5000,message})
|
|
|
+ return
|
|
|
+ }
|
|
|
+ barcodeNumberTrueFalseBy.value=false
|
|
|
+ cutBarcode(matchBarcodeList.value, barcodeNumber.value)
|
|
|
+}
|
|
|
+const beforeClose= (action) =>
|
|
|
+ new Promise((resolve) => {
|
|
|
+ if(action==='confirm'){
|
|
|
+ if(!barcodeNumber.value){
|
|
|
+ tips.value='请输入数量'
|
|
|
+ showToast({duration:5000,message:'请输入数量'})
|
|
|
+ return resolve(false)
|
|
|
+ }
|
|
|
+ const allCount = matchBarcodeList.value.reduce((sum, item) => sum + Number(item.qty), 0)
|
|
|
+ if(Number(barcodeNumber.value)>allCount){
|
|
|
+ const message='数量不能大于最大数量'+allCount
|
|
|
+ tips.value=message
|
|
|
+ showToast({duration:5000,message})
|
|
|
+ return resolve(false)
|
|
|
+ }
|
|
|
+ resolve(true)
|
|
|
+ cutBarcode(matchBarcodeList.value, barcodeNumber.value)
|
|
|
+ }else {
|
|
|
+ tips.value='您已取消扣减扫描商品,请重新扫描'
|
|
|
+ scanBarcode.value=''
|
|
|
+ matchBarcodeList.value=[]
|
|
|
+ resolve(true)
|
|
|
+ }
|
|
|
+
|
|
|
+ });
|
|
|
+const cutBarcode = (list, count) => { //扣减数量
|
|
|
+ let remainingCount = count // 剩余的扣减数量
|
|
|
+ // 更新扫描数据的逻辑
|
|
|
+ const updateData = (item) => {
|
|
|
+ const itemIndex = dataList.value.findIndex(data => data.lotNum === item.lotNum)
|
|
|
+ const deductedAmount = item.originalDetailAmount - item.qty // 扣减的数量
|
|
|
+ if (itemIndex !== -1) {
|
|
|
+ dataList.value[itemIndex] = {
|
|
|
+ ...dataList.value[itemIndex],
|
|
|
+ quantity: dataList.value[itemIndex].quantity + deductedAmount, // 更新实际扣减的数量
|
|
|
+ oldQuantity:dataList.value[itemIndex].oldQuantity + deductedAmount, // 更新实际扣减的数量
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ item.quantity = deductedAmount
|
|
|
+ item.oldQuantity=deductedAmount
|
|
|
+ dataList.value.push(item)
|
|
|
+ }
|
|
|
+ }
|
|
|
+ list.forEach(item => {
|
|
|
+ if (remainingCount <= 0) return // 如果剩余数量为0,停止扣减
|
|
|
+ item.originalDetailAmount = item.qty // 保存原始数量
|
|
|
+ if (item.qty > 0) {
|
|
|
+ // 如果剩余数量大于当前商品的数量,则直接扣除当前商品的数量
|
|
|
+ if (remainingCount >= item.qty) {
|
|
|
+ remainingCount -= item.qty
|
|
|
+ item.qty = 0
|
|
|
+ } else {
|
|
|
+ item.qty -= remainingCount // 扣减剩余数量
|
|
|
+ remainingCount = 0
|
|
|
+ }
|
|
|
+ item.isPacking=true
|
|
|
+ }
|
|
|
+ if (item.qty !== item.originalDetailAmount) {
|
|
|
+ updateData(item) // 更新扫描数据
|
|
|
+ scanBarcode.value = ''
|
|
|
+ tips.value = '请继续扫描商品'
|
|
|
+ scanSuccess()
|
|
|
+ }
|
|
|
+ })
|
|
|
+ const materiaList=orderList.value.filter(item=>item.status=='600' && item.qty>0)
|
|
|
+ const endOrder=orderList.value.filter(item=>item.status=='60' && item.qty>0)
|
|
|
+ if(materiaList.length ==0 &&endOrder.length==0){
|
|
|
+ setPacking('single')
|
|
|
+ return
|
|
|
+ }
|
|
|
+}
|
|
|
+// 进行装箱
|
|
|
+const checkPackingRef=ref(null)
|
|
|
+const currPackingList=ref([])
|
|
|
+const batchPackingRef=ref(null)
|
|
|
+const setPacking=(type)=>{
|
|
|
+ if(!printer.value){
|
|
|
+ scanError()
|
|
|
+ showNotify({ type: 'warning', duration: 3000, message: '请先设置打印机' })
|
|
|
+ return
|
|
|
+ }
|
|
|
+ // 获取装箱的商品列表
|
|
|
+ currPackingList.value = orderList.value.filter(item => item.isPacking)
|
|
|
+ if (currPackingList.value.length === 0) {
|
|
|
+ scanError()
|
|
|
+ showNotify({ type: 'warning', duration: 3000, message: '暂无未装箱数据' })
|
|
|
+ return
|
|
|
+ }
|
|
|
+ const materiaList = orderList.value.filter(item => item.status == '600' && item.qty > 0)
|
|
|
+ if (materiaList.length > 0) {
|
|
|
+ const checkBarcode = new Set(currPackingList.value.flatMap(item => item.relatedMaterial.map(material => material.barCode)))
|
|
|
+ const packingBarcodes = new Set(materiaList.map(item => item.barcode))
|
|
|
+ // 判断是否有装箱商品条形码与需要扫描的物料条形码重复
|
|
|
+ const hasCommonBarcode = [...packingBarcodes].some(barcode => checkBarcode.has(barcode))
|
|
|
+ if (hasCommonBarcode) {
|
|
|
+ scanError();
|
|
|
+ showNotify({ type: 'warning', duration: 3000, message: `装箱商品包含耗材${[...checkBarcode].join(',')},请先扫描耗材` })
|
|
|
+ return
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (type === 'single') { // 普通装箱
|
|
|
+ checkPackingRef.value?.show(currPackingList.value, orderDetail.value)
|
|
|
+ } else { // 批量装箱
|
|
|
+ const list =orderList.value.filter(item => item.isPacking && item.status=='60')
|
|
|
+ if (list.length > 1) {
|
|
|
+ scanError()
|
|
|
+ showNotify({ type: 'warning', duration: 3000, message: '不支持多个商品装箱' })
|
|
|
+ return
|
|
|
+ }
|
|
|
+ batchPackingRef.value?.show(currPackingList.value, orderDetail.value)
|
|
|
+ }
|
|
|
+}
|
|
|
+//重置装箱状态
|
|
|
+const resetPackingStatus=()=>{
|
|
|
+ currPackingList.value.forEach((item) => {
|
|
|
+ item.quantity=0
|
|
|
+ delete item.isPacking
|
|
|
+ })
|
|
|
+}
|
|
|
+//重置装箱
|
|
|
+const packingListRef=ref(null)
|
|
|
+const resetPacking=()=>{
|
|
|
+ packingListRef.value?.show(orderDetail.value.orderPacking,orderDetail.value)
|
|
|
+}
|
|
|
+
|
|
|
+//重新开始
|
|
|
+const reset=()=>{
|
|
|
+ showConfirmDialog({
|
|
|
+ title: '温馨提示',
|
|
|
+ message: '您正在进行重新开始操作,是否继续?',
|
|
|
+ }).then(() => {loadData()})
|
|
|
+}
|
|
|
+//打印清单
|
|
|
+const printerRef=ref(null)
|
|
|
+//设置打印机
|
|
|
+const setPrinter=()=>{
|
|
|
+ printerRef.value?.show(warehouse)
|
|
|
+}
|
|
|
+const printer=ref(null)
|
|
|
+const print=(templateCode,code)=>{
|
|
|
+ if(!printer.value){
|
|
|
+ scanError()
|
|
|
+ showNotify({ type: 'warning', duration: 3000, message: '请先设置打印机' });
|
|
|
+ return
|
|
|
+ }
|
|
|
+ const data = {warehouse,code,printServer: printer.value.server, printName:printer.value.printer,templateCode }
|
|
|
+ showLoading()
|
|
|
+ fluxPrint(data)
|
|
|
+ .then(res => {
|
|
|
+ scanSuccess()
|
|
|
+ showNotify({ type: 'success', duration: 3000, message: '打印已发起,请检查打印情况' });
|
|
|
+ })
|
|
|
+ .catch(err => {
|
|
|
+ scanError()
|
|
|
+ tips.value=err.message || '系统异常,请联系技术支持!'
|
|
|
+ }).finally(() => {
|
|
|
+ closeLoading()
|
|
|
+ })
|
|
|
+
|
|
|
+}
|
|
|
+const onPrint=(code)=>{
|
|
|
+ printer.value=code
|
|
|
+}
|
|
|
+//设置订单号
|
|
|
+const setBarcode = (code) => {
|
|
|
+ const data = { warehouse, code, activityOrderFlag: true }
|
|
|
+ showLoading()
|
|
|
+ getPendingReviewTask(data).then(res => {
|
|
|
+ if (res.data.details.length == 0) {
|
|
|
+ scanError()
|
|
|
+ inputBarcodeRef.value?.show('', '请扫描订单/快递单号', '暂未查询到待复核数据,请切换单号')
|
|
|
+ } else {
|
|
|
+ if(res.data.releaseStatus=='H' || res.data.status=='90' ||res.data.erpCancelFlag=='Y'){
|
|
|
+ scanError()
|
|
|
+ cancelOrder(res.data)
|
|
|
+ return
|
|
|
+ }
|
|
|
+ if(res.data.waveType!=='M'){
|
|
|
+ scanError()
|
|
|
+ inputBarcodeRef.value?.show('', '请扫描订单/快递单号', '仅支持大件单复核','')
|
|
|
+ return
|
|
|
+ }
|
|
|
+ orderNo.value = code
|
|
|
+ orderDetail.value = res.data
|
|
|
+ tips.value = '请扫描商品条码'
|
|
|
+ scanSuccess()
|
|
|
+ // 处理每个详情项
|
|
|
+ res.data.details.forEach((item) => {
|
|
|
+ item.quantity = 0
|
|
|
+ item.oldQuantity = 0
|
|
|
+ item.oldQty = item.qty
|
|
|
+ if (item.relatedMaterial == null) {
|
|
|
+ item.relatedMaterial = []
|
|
|
+ }
|
|
|
+ if (item.universalBarcode) {
|
|
|
+ item.universalCode = '#@@@@@@#'
|
|
|
+ }
|
|
|
+ })
|
|
|
+ const relatedMaterialList = getRelatedMaterial(res.data.details)
|
|
|
+ res.data.details.push(...relatedMaterialList)
|
|
|
+ dataList.value = res.data.details
|
|
|
+ isUniqueCode.value = dataList.value.some(item => item.uniqueRegExp || item.imeiRegExp)
|
|
|
+ scanBarcode.value = ''
|
|
|
+ }
|
|
|
+ }).catch(err => {
|
|
|
+ scanError()
|
|
|
+ inputBarcodeRef.value?.show('', '请扫描订单/快递单号', err.message)
|
|
|
+ }).finally(f => {
|
|
|
+ closeLoading()
|
|
|
+ })
|
|
|
+}
|
|
|
+const containerNoMap={
|
|
|
+ 'WH01':'FJ-WH01-20',
|
|
|
+ 'WH02':'FJ-WH02-20',
|
|
|
+ 'WH10':'FJ-WH10-01',
|
|
|
+ 'WH99':'FJ-WH99-01',
|
|
|
+}
|
|
|
+//返拣容器
|
|
|
+const cancelOrder=(item,type)=>{
|
|
|
+ const orderDetailStatus = orderList.value.find(item => (item.status != '60' && item.status != '600'));
|
|
|
+ if(item.status=='90'){
|
|
|
+ showDialog({ title: '温馨提示', message: '已取消, 暂停发货', }).then(() => {
|
|
|
+ inputBarcodeRef.value?.show('', '请扫描订单/快递单号', '上一单为冻结单,请重新扫描单号')
|
|
|
+ });
|
|
|
+ }else if(item.releaseStatus=='H'){
|
|
|
+ showDialog({ title: '温馨提示', message: '已冻结, 暂停发货', }).then(() => {
|
|
|
+ inputBarcodeRef.value?.show('', '请扫描订单/快递单号', '上一单为冻结单,请重新扫描单号')
|
|
|
+ });
|
|
|
+ }else if(orderDetailStatus && item.erpCancelFlag=='Y' ){
|
|
|
+ showDialog({ title: '温馨提示', message: '此取消单包含《待拣货》商品,请将所有商品拣货后返拣', }).then(() => {});
|
|
|
+ } else if(item.erpCancelFlag=='Y' || type=='erp'){
|
|
|
+ showConfirmDialog({ title: '温馨提示', message: '订单为取消单,请进入还库流程!!!', })
|
|
|
+ .then(() => {
|
|
|
+ _reversePicking()
|
|
|
+ })
|
|
|
+ }
|
|
|
+}
|
|
|
+const _reversePicking = () => {
|
|
|
+ showLoading()
|
|
|
+ const data = {
|
|
|
+ warehouse,
|
|
|
+ reversePickingContainerNo: containerNoMap[warehouse],
|
|
|
+ code: orderDetail.value.orderNo,
|
|
|
+ }
|
|
|
+ reversePicking(data).then(res => {
|
|
|
+ showNotify({ type: 'success', duration: 5000, message: `${data.code},已进行返拣,请放置《${data.reversePickingContainerNo}》返拣容器中!` })
|
|
|
+ loadData()
|
|
|
+ }).finally(() => {
|
|
|
+ closeLoading()
|
|
|
+ })
|
|
|
+}
|
|
|
+
|
|
|
+const rowStyle=( row )=>{
|
|
|
+ if(row.isPacking){
|
|
|
+ return { background: '#E6A23C'}
|
|
|
+ }
|
|
|
+ if( row.status=='600'){
|
|
|
+ return { background: '#fff8d9'}
|
|
|
+ }
|
|
|
+ if(row.status!='60' ){
|
|
|
+ return { background: '#b3b3b3'}
|
|
|
+ }
|
|
|
+
|
|
|
+ return ''
|
|
|
+}
|
|
|
+//条码匹配放到前边
|
|
|
+const barcodeMatching = (checkBarcode) => {
|
|
|
+ return dataList.value.reduce((list, item) => {
|
|
|
+ if (item.status === '50') {
|
|
|
+ list.push(item)
|
|
|
+ return list
|
|
|
+ }
|
|
|
+ const itemBarcode = barcodeToUpperCase(item.barcode)
|
|
|
+ const isMatchingBarcode = itemBarcode === checkBarcode || checkBarcode === item.sku || checkBarcode === item.barcodeOne
|
|
|
+ if (isMatchingBarcode) {
|
|
|
+ list.unshift(item) // 匹配条形码的项放到顶部
|
|
|
+ } else {
|
|
|
+ list.push(item) // 不匹配的项放到末尾
|
|
|
+ }
|
|
|
+ return list
|
|
|
+ }, [])
|
|
|
+}
|
|
|
+// 格式化耗材
|
|
|
+const getRelatedMaterial = (data) => {
|
|
|
+ const materialMap = {}
|
|
|
+ let allocationIdCounter = 0
|
|
|
+ data.forEach(item => {
|
|
|
+ if (item.status == '60' && item.qty>0) {
|
|
|
+ item.relatedMaterial.forEach((material, index) => {
|
|
|
+ material.oldQty = material.qty * item.qty
|
|
|
+ material.qty = material.qty * item.qty
|
|
|
+ material.barcode = material.barCode
|
|
|
+ material.barcode2 = material.barCode
|
|
|
+ material.qtyOrdered = null
|
|
|
+ material.skuName = material.skuDescr
|
|
|
+ material.quantity = 0
|
|
|
+ material.status = '600'
|
|
|
+ material.lotNum = allocationIdCounter++
|
|
|
+ material.relatedMaterial = []
|
|
|
+ if (materialMap[material.barcode]) {
|
|
|
+ materialMap[material.barcode].qty += material.qty
|
|
|
+ } else {
|
|
|
+ materialMap[material.barcode] = { ...material }
|
|
|
+ }
|
|
|
+ })
|
|
|
+ }
|
|
|
+ })
|
|
|
+ return Object.values(materialMap)
|
|
|
+}
|
|
|
+
|
|
|
+//切换波次
|
|
|
+const _setOrderNo = () => {
|
|
|
+ back.value = false
|
|
|
+ inputBarcodeRef.value?.show('', '请扫描订单/快递单号', '')
|
|
|
+}
|
|
|
+// 数据刷新
|
|
|
+const loadData = () => {
|
|
|
+ if (!orderNo.value) {
|
|
|
+ inputBarcodeRef.value?.show('', '请扫描订单/快递单号', '')
|
|
|
+ return
|
|
|
+ } else {
|
|
|
+ setBarcode(orderNo.value)
|
|
|
+ }
|
|
|
+}
|
|
|
+onUnmounted(() => {
|
|
|
+ closeListener()
|
|
|
+})
|
|
|
+
|
|
|
+// window.onRefresh = loadData
|
|
|
+</script>
|
|
|
+
|
|
|
+<style scoped lang="sass">
|
|
|
+.container
|
|
|
+ background: #e9f4ff
|
|
|
+
|
|
|
+ .large
|
|
|
+ .large-title
|
|
|
+ display: flex
|
|
|
+ justify-content: space-between
|
|
|
+ padding: 8px 10px
|
|
|
+
|
|
|
+ .large-tips
|
|
|
+ color: #ed6a0c
|
|
|
+ flex: 1
|
|
|
+
|
|
|
+ .scan-barcode
|
|
|
+ ::v-deep(.van-cell)
|
|
|
+ padding: 5px 15px 0 15px
|
|
|
+
|
|
|
+ ::v-deep(.van-field__control)
|
|
|
+ border-bottom: 2px solid #efefef
|
|
|
+ font-size: 16px
|
|
|
+
|
|
|
+ ::v-deep(.van-field__label)
|
|
|
+ width: unset
|
|
|
+ font-size: 16px
|
|
|
+
|
|
|
+ .input-barcode
|
|
|
+ ::v-deep(.van-field__control)
|
|
|
+ border-bottom: 2px solid #0077ff
|
|
|
+ z-index: 2
|
|
|
+
|
|
|
+ .order-detail
|
|
|
+ margin-top: 2px
|
|
|
+ background: #fff
|
|
|
+ font-size: 14px
|
|
|
+
|
|
|
+ .picking-no
|
|
|
+ display: flex
|
|
|
+ justify-content: space-between
|
|
|
+ margin: 0 15px
|
|
|
+ padding: 8px 0
|
|
|
+ border-bottom: 1px solid #eaeaeb
|
|
|
+ .picking-container
|
|
|
+ padding: 0 15px
|
|
|
+ text-align: left
|
|
|
+ border-bottom: 1px solid #eaeaeb
|
|
|
+
|
|
|
+ .container-item
|
|
|
+ line-height: 30px
|
|
|
+ display: flex
|
|
|
+ align-items: center
|
|
|
+
|
|
|
+ .picking-order-count
|
|
|
+ display: flex
|
|
|
+ justify-content: space-between
|
|
|
+ line-height: 30px
|
|
|
+
|
|
|
+ .picking-button
|
|
|
+ display: flex
|
|
|
+ justify-content: space-evenly
|
|
|
+ align-items: center
|
|
|
+
|
|
|
+ .picking-button-item
|
|
|
+ flex: 1
|
|
|
+ color: #419bff
|
|
|
+ font-weight: bold
|
|
|
+ line-height: 35px
|
|
|
+ border-right: 1px solid #eaeaeb
|
|
|
+ box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.1)
|
|
|
+
|
|
|
+ .picking-button-item:last-child
|
|
|
+ border-right: none
|
|
|
+
|
|
|
+ .order-list-box
|
|
|
+ background: #fff
|
|
|
+ margin-top: 2px
|
|
|
+
|
|
|
+ .order-list
|
|
|
+ width: 100%
|
|
|
+ overflow-y: auto
|
|
|
+ max-height: 60vh
|
|
|
+
|
|
|
+ .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
|
|
|
+ .count-input
|
|
|
+ border-bottom: 2px solid #0077ff
|
|
|
+
|
|
|
+</style>
|