|
|
@@ -0,0 +1,546 @@
|
|
|
+<template>
|
|
|
+ <div class="container">
|
|
|
+ <van-nav-bar
|
|
|
+ title="还库任务-分格口"
|
|
|
+ left-arrow
|
|
|
+ fixed
|
|
|
+ placeholder
|
|
|
+ @click-left="onClickLeft"
|
|
|
+ >
|
|
|
+ <template #left>
|
|
|
+ <van-icon name="arrow-left" size="25"/>
|
|
|
+ <div style="color: #fff">返回</div>
|
|
|
+ </template>
|
|
|
+ <template #right>
|
|
|
+ <div style="color: #fff;line-height: 46px " @click="onComplete">完成</div>
|
|
|
+ <div style="padding:14px 0 12px 6px" @click="onClickRightIcon">
|
|
|
+ <van-icon name="list-switch" size="25"/>
|
|
|
+ </div>
|
|
|
+ </template>
|
|
|
+ </van-nav-bar>
|
|
|
+ <div class="move-stock">
|
|
|
+ <div class="code">
|
|
|
+ <div class="code-title">
|
|
|
+ <div>{{ containerNo || '' }}</div>
|
|
|
+ <div class="code-tips">
|
|
|
+ <van-notice-bar :background="'none'" :speed="50" :text="tips"/>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <div class="code-input">
|
|
|
+ <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>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <div class="move-stock-content">
|
|
|
+ <table class="compact-table">
|
|
|
+ <colgroup>
|
|
|
+ <col v-for="i in 10" style="width: 10%;">
|
|
|
+ </colgroup>
|
|
|
+ <tbody>
|
|
|
+ <tr>
|
|
|
+ <td colspan="3">格口</td>
|
|
|
+ <td colspan="7">{{ bin }}</td>
|
|
|
+ </tr>
|
|
|
+ </tbody>
|
|
|
+ </table>
|
|
|
+ </div>
|
|
|
+ <div class="move-stock-list">
|
|
|
+ <table class="task-table">
|
|
|
+ <thead>
|
|
|
+ <tr>
|
|
|
+ <th>商品条码</th>
|
|
|
+ <th>商品名称</th>
|
|
|
+ <th>格口号</th>
|
|
|
+ <th>数量</th>
|
|
|
+ </tr>
|
|
|
+ </thead>
|
|
|
+ <tbody>
|
|
|
+ <tr v-for="(item, index) in binList" :key="index" v-if="binList.length>0">
|
|
|
+ <td>{{ item.barcode }}</td>
|
|
|
+ <td>{{ item.skuName }}</td>
|
|
|
+ <td>{{ item.slot }}</td>
|
|
|
+ <td>{{ item.qty }}</td>
|
|
|
+ </tr>
|
|
|
+ <tr v-else>
|
|
|
+ <td colspan="4">
|
|
|
+ <van-empty :image="nodataUrl" image-size="120"/>
|
|
|
+ </td>
|
|
|
+ </tr>
|
|
|
+ </tbody>
|
|
|
+ </table>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <!-- 弹出框 -->
|
|
|
+ <van-action-sheet
|
|
|
+ v-model:show="modeTrueFalseBy"
|
|
|
+ :actions="actions"
|
|
|
+ cancel-text="取消"
|
|
|
+ close-on-click-action
|
|
|
+ @select="onSelectMode"
|
|
|
+ />
|
|
|
+ <!-- 单据选择-->
|
|
|
+ <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.lotNum,item.customerId);barcodeActive=item;lotBarcodeTrueFalseBy=false">
|
|
|
+ <template #title>
|
|
|
+ {{ item.sku }}({{ item.availableQty }}件)
|
|
|
+ </template>
|
|
|
+ <template #label>
|
|
|
+ 生产日期:{{ item.productionDate || '--' }}-失效日期:{{ item.expirationDate || '--' }}
|
|
|
+ </template>
|
|
|
+ </van-cell>
|
|
|
+ </van-cell-group>
|
|
|
+ </van-action-sheet>
|
|
|
+ </div>
|
|
|
+</template>
|
|
|
+
|
|
|
+<script setup>
|
|
|
+import {onMounted, onUnmounted, ref} from 'vue'
|
|
|
+import {useRouter, useRoute} from 'vue-router'
|
|
|
+import {useStore} from '@/store/modules/user'
|
|
|
+import {androidFocus, getHeader, goBack, scanError, scanSuccess} from '@/utils/android'
|
|
|
+import {closeListener, openListener, scanInit} from '@/utils/keydownListener'
|
|
|
+import {getInventoryList} from '@/api/check/index'
|
|
|
+import {closeLoading, showLoading} from '@/utils/loading'
|
|
|
+import nodataUrl from '@/assets/nodata.png'
|
|
|
+import {showConfirmDialog, showDialog, showNotify, showToast} from 'vant'
|
|
|
+import {getRecommendedLocation} from "@/api/haikang/index";
|
|
|
+import {
|
|
|
+ createReturnFirstSeed,
|
|
|
+ getReturnTaskBinList,
|
|
|
+ returnTaskAbandon,
|
|
|
+ returnTaskFirstStepComplete
|
|
|
+} from "@/api/returnTask/index";
|
|
|
+
|
|
|
+const router = useRouter()
|
|
|
+const route = useRoute()
|
|
|
+const store = useStore()
|
|
|
+try {
|
|
|
+ getHeader()
|
|
|
+ androidFocus()
|
|
|
+} catch (error) {
|
|
|
+ router.push('/login')
|
|
|
+}
|
|
|
+const warehouse = store.warehouse
|
|
|
+
|
|
|
+const pattern = /^[1-9]\d*$/
|
|
|
+// 容器号和扫描类型的状态
|
|
|
+const taskNo = ref(route.query.code)
|
|
|
+const containerNo = ref(route.query.container)
|
|
|
+//扫描类型
|
|
|
+const scanType = ref(2)
|
|
|
+const searchRef = ref(null)
|
|
|
+//扫描条码
|
|
|
+const searchBarcode = ref('')
|
|
|
+//扫描库位
|
|
|
+const location = ref('')
|
|
|
+//批次数据
|
|
|
+const lotBarcodeList = ref([])
|
|
|
+const lotBarcodeTrueFalseBy = ref(false)
|
|
|
+const barcodeActive = ref({})
|
|
|
+//格口
|
|
|
+const bin = ref('-')
|
|
|
+const binList = ref([])
|
|
|
+const model = ref({})
|
|
|
+const countRef = ref(null)
|
|
|
+const back = ref(true)
|
|
|
+// 页面初始化
|
|
|
+onMounted(() => {
|
|
|
+ openListener()
|
|
|
+ scanInit(_handlerScan)
|
|
|
+ loadData()
|
|
|
+})
|
|
|
+//切换模式
|
|
|
+const actions = [
|
|
|
+ {name: '放弃', key: 'abandon'}
|
|
|
+]
|
|
|
+const modeTrueFalseBy = ref(false)
|
|
|
+
|
|
|
+// 扫描条码监听
|
|
|
+const _handlerScan = (code) => {
|
|
|
+ if (scanType.value === 2) {
|
|
|
+ setTimeout(() => {
|
|
|
+ _getInventoryList(code)
|
|
|
+ }, 200)
|
|
|
+ }
|
|
|
+}
|
|
|
+// 获取库存数据
|
|
|
+const _getInventoryList = async (barcode) => {
|
|
|
+ const data = {warehouse, location: containerNo.value, barcode}
|
|
|
+ try {
|
|
|
+ showLoading()
|
|
|
+ const res = await getInventoryList(data)
|
|
|
+ closeLoading()
|
|
|
+ if (res.data.length === 0) {
|
|
|
+ scanError()
|
|
|
+ searchBarcode.value = ''
|
|
|
+ showNotify({duration: 5000, message: `条码:${barcode},未找到可还库库存,请检查条码!`})
|
|
|
+ tips.value = `条码:${barcode},未找到可还库库存,请检查条码!`
|
|
|
+ return
|
|
|
+ }
|
|
|
+ barcodeActive.value = {}
|
|
|
+ lotBarcodeList.value = res.data
|
|
|
+ searchBarcode.value = res.data[0].sku
|
|
|
+ if (lotBarcodeList.value.length == 1) {
|
|
|
+ barcodeActive.value = lotBarcodeList.value[0]
|
|
|
+ await _getRecommendedLocation(lotBarcodeList.value[0].lotNum, lotBarcodeList.value[0].customerId)
|
|
|
+ } else if (lotBarcodeList.value.length > 1) {
|
|
|
+ lotBarcodeTrueFalseBy.value = true
|
|
|
+ }
|
|
|
+
|
|
|
+ } catch (err) {
|
|
|
+ closeLoading()
|
|
|
+ console.error(err)
|
|
|
+ }
|
|
|
+}
|
|
|
+// 获取库存数据
|
|
|
+const _getRecommendedLocation = async (lotNum, owner) => {
|
|
|
+ try {
|
|
|
+ const params = {warehouse, lotNum, owner, zoneGroup: 'WH01-01'}
|
|
|
+ const res = await getRecommendedLocation(params)
|
|
|
+ // '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 setLocation = (item) => {
|
|
|
+ const data = {
|
|
|
+ taskNo: taskNo.value,
|
|
|
+ barcode: searchBarcode.value,
|
|
|
+ lotNum: barcodeActive.value.lotNum,
|
|
|
+ containerCode: item.location
|
|
|
+ }
|
|
|
+ createReturnFirstSeed(data).then(res => {
|
|
|
+ scanSuccess()
|
|
|
+ searchBarcode.value = ''
|
|
|
+ bin.value = res.data
|
|
|
+ tips.value = `请扫描商品条码`
|
|
|
+ getTaskBinList()
|
|
|
+ }).catch(err => {
|
|
|
+ scanError()
|
|
|
+ barcodeActive.value = {}
|
|
|
+ searchBarcode.value = ''
|
|
|
+ bin.value = '-'
|
|
|
+ tips.value = `${err.message}`
|
|
|
+ })
|
|
|
+}
|
|
|
+
|
|
|
+// 提示文本根据扫描类型返回
|
|
|
+const tips = ref('请扫描商品条码')
|
|
|
+const onSelectMode = async (value) => {
|
|
|
+ if (value.key == 'abandon') {
|
|
|
+ showDialog({
|
|
|
+ title: '温馨提示',
|
|
|
+ message: '您正在进行放弃任务操作,是否继续?',
|
|
|
+ }).then(() => {
|
|
|
+ showLoading()
|
|
|
+ returnTaskAbandon({taskNo: taskNo.value}).then(res => {
|
|
|
+ router.push({name: 'ReturnList'})
|
|
|
+ showToast({duration: 3000, message: '当前任务已放弃正在跳转到任务页面,请稍后~'})
|
|
|
+ }).catch((err) => {
|
|
|
+ tips.value = `${err.message}`
|
|
|
+ }).finally(_ => {
|
|
|
+ closeLoading()
|
|
|
+ })
|
|
|
+ });
|
|
|
+
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+const getTaskBinList = () => {
|
|
|
+ getReturnTaskBinList({taskNo: taskNo.value}).then(res => {
|
|
|
+ binList.value = res.data.sort((a, b) => {
|
|
|
+ if (a.slot < b.slot) {
|
|
|
+ return 1;
|
|
|
+ }
|
|
|
+ if (a.slot > b.slot) {
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+ return 0
|
|
|
+ });
|
|
|
+ }).catch(err => {
|
|
|
+ scanError()
|
|
|
+ tips.value = `${err.message}`
|
|
|
+ showNotify({type: 'danger', duration: 3000, message: `${err.message}`})
|
|
|
+ })
|
|
|
+}
|
|
|
+const onClickRightIcon = () => {
|
|
|
+ modeTrueFalseBy.value = true
|
|
|
+}
|
|
|
+// 完成任务
|
|
|
+const onComplete = () => {
|
|
|
+ showConfirmDialog({
|
|
|
+ title: '温馨提示',
|
|
|
+ message:
|
|
|
+ '您正在进行完成操作,是否立即呼叫小车?',
|
|
|
+ confirmButtonText: '立即呼叫',
|
|
|
+ cancelButtonText: '不呼叫',
|
|
|
+ })
|
|
|
+ .then(() => {
|
|
|
+ _returnTaskFirstStepComplete(true)
|
|
|
+ })
|
|
|
+ .catch(() => {
|
|
|
+ _returnTaskFirstStepComplete(false)
|
|
|
+ });
|
|
|
+}
|
|
|
+const _returnTaskFirstStepComplete=(callHikQuickIn)=>{
|
|
|
+ showLoading()
|
|
|
+ returnTaskFirstStepComplete({taskNo:taskNo.value,callHikQuickIn}).then(res => {
|
|
|
+ if(callHikQuickIn){
|
|
|
+ router.replace({ name: 'ReturnTask', query: { code:taskNo.value,container:containerNo.value } });
|
|
|
+ }else {
|
|
|
+ router.push({name: 'ReturnList'})
|
|
|
+ }
|
|
|
+ }).finally(_ => {
|
|
|
+ closeLoading()
|
|
|
+ })
|
|
|
+}
|
|
|
+// 数据刷新
|
|
|
+const loadData = () => {
|
|
|
+ scanType.value = 2
|
|
|
+ getTaskBinList()
|
|
|
+ setTimeout(() => {
|
|
|
+ if (binList.value.length > 0) {
|
|
|
+ bin.value = binList.value[0].slot
|
|
|
+ }
|
|
|
+ }, 400)
|
|
|
+}
|
|
|
+
|
|
|
+const onClickLeft = () => {
|
|
|
+ router.push({name:'ReturnList'})
|
|
|
+};
|
|
|
+
|
|
|
+onUnmounted(() => {
|
|
|
+ closeListener()
|
|
|
+})
|
|
|
+
|
|
|
+window.onRefresh = loadData
|
|
|
+</script>
|
|
|
+
|
|
|
+<style scoped lang="scss">
|
|
|
+.container {
|
|
|
+ .move-stock {
|
|
|
+ .code {
|
|
|
+ background: #e9f4ff;
|
|
|
+ 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;
|
|
|
+ font-size: 16px;
|
|
|
+ }
|
|
|
+
|
|
|
+ ::v-deep(.van-search__field) {
|
|
|
+ border-bottom: 2px solid #ffffff;
|
|
|
+ height: 50px;
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ }
|
|
|
+
|
|
|
+ ::v-deep(.van-search__content) {
|
|
|
+ background: #fff;
|
|
|
+ height: 50px;
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ }
|
|
|
+
|
|
|
+ ::v-deep(.van-field__control) {
|
|
|
+ font-size: 16px;
|
|
|
+ height: 50px;
|
|
|
+ line-height: 50px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .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;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ .nav-right {
|
|
|
+ padding: 14px 0 12px 5px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .move-stock-list {
|
|
|
+ width: 100%;
|
|
|
+ overflow-y: auto;
|
|
|
+ max-height: 280px;
|
|
|
+ min-height: 100px;
|
|
|
+
|
|
|
+ .move-button {
|
|
|
+ background: #1989fa;
|
|
|
+ color: #fff;
|
|
|
+ width: 100%;
|
|
|
+ height: 30px;
|
|
|
+ font-size: 14px;
|
|
|
+ line-height: 30px;
|
|
|
+ font-weight: bold;
|
|
|
+ }
|
|
|
+
|
|
|
+ .task-table,
|
|
|
+ .task-table-bin,
|
|
|
+ .task-table-box {
|
|
|
+ width: 100%;
|
|
|
+ table-layout: fixed;
|
|
|
+ border-collapse: collapse;
|
|
|
+ font-size: 13px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .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: 13px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .task-table-bin thead {
|
|
|
+ background-color: #3f8dff;
|
|
|
+ }
|
|
|
+
|
|
|
+ .task-table-bin tbody {
|
|
|
+ background: #cde7ff;
|
|
|
+ }
|
|
|
+
|
|
|
+ .task-table tbody tr.pricking-active {
|
|
|
+ background-color: #d6f9e7;
|
|
|
+ }
|
|
|
+
|
|
|
+ .task-table tbody tr.stock-active {
|
|
|
+ background-color: #fffadd;
|
|
|
+ }
|
|
|
+
|
|
|
+ .task-table tbody tr.virtual-active {
|
|
|
+ background-color: #cacaca;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ .move-stock-content {
|
|
|
+ margin-bottom: 10px;
|
|
|
+
|
|
|
+ .compact-table {
|
|
|
+ width: 100%;
|
|
|
+ border-collapse: collapse;
|
|
|
+ margin: 0;
|
|
|
+ font-size: 14px;
|
|
|
+ line-height: 1.2;
|
|
|
+ border: 1px solid #ccc;
|
|
|
+
|
|
|
+ td {
|
|
|
+ padding: 8px 12px;
|
|
|
+ border: 1px solid #ccc;
|
|
|
+ background: transparent;
|
|
|
+ text-align: center;
|
|
|
+ }
|
|
|
+
|
|
|
+ td:first-child {
|
|
|
+ color: #333;
|
|
|
+ font-size: 25px;
|
|
|
+ }
|
|
|
+
|
|
|
+ td:last-child {
|
|
|
+ color: #e63535;
|
|
|
+ font-size: 50px;
|
|
|
+
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+.count-input {
|
|
|
+ ::v-deep(.van-field__value) {
|
|
|
+ border-bottom: 2px solid #0077ff;
|
|
|
+ font-size: 16px;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+.completion {
|
|
|
+ text-align: right;
|
|
|
+ font-size: 14px;
|
|
|
+ line-height: 35px;
|
|
|
+ color: #0077ff;
|
|
|
+ padding: 0 10px;
|
|
|
+ cursor: pointer;
|
|
|
+ text-decoration: underline;
|
|
|
+}
|
|
|
+
|
|
|
+.tips {
|
|
|
+ font-size: 13px;
|
|
|
+ text-align: left;
|
|
|
+ padding: 5px 15px;
|
|
|
+}
|
|
|
+</style>
|