| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479 |
- <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" style="color: #fff" @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
- class="code-bin"
- ref="searchRef"
- v-model="bin"
- placeholder="分配格口"
- label="分配格口:"
- readonly
- 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 { showConfirmDialog, 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 { finishTask, getRecommendedLocation, getWaitPutawayList, setBindAllocateWall } from '@/api/haikang'
- import { barcodeToUpperCase } from '@/utils/dataType'
- import { closeLoading, showLoading } from '@/utils/loading'
- try {
- getHeader()
- androidFocus()
- } catch (error) {
- }
- // 页面初始化
- onMounted(() => {
- openListener()
- scanInit(_handlerScan)
- loadData()
- })
- const store = useStore()
- 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,
- asnCode: barcodeActive.value.asnNo,
- 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()
- })
- //删除分拨
- const onClickRight = () => {
- showConfirmDialog({
- title: '温馨提示',
- message:'您正在进行释放分拨墙是否继续?',
- keyboardEnabled:false
- }).then(() => {
- showLoading()
- const params={warehouse,container:containerNo.value}
- finishTask(params).then(res=>{
- showNotify({ type: 'success', duration: 3000, message: `解绑成功` })
- scanSuccess()
- reset()
- loadData()
- }).catch(err=>{
- scanError()
- }).finally(() => {
- closeLoading()
- })
- }).catch(() => {})
- }
- const reset=()=>{
- containerNo.value=''
- wallNo.value=''
- scanType.value=3
- searchBarcode.value = ''
- bin.value=''
- locationActive.value = []
- tips.value='请扫描容器号'
- }
- window.onRefresh = loadData
- </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-bin
- ::v-deep(.van-field__control)
- font-size: 20px
- color: #ff0d00
- .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>
|