| New file |
| | |
| | | <template> |
| | | <view class="page-container"> |
| | | <!-- 表单区域 --> |
| | | <view class="form-section"> |
| | | <view class="form-item"> |
| | | <view class="form-label"> |
| | | <uni-icons type="scan" size="18" color="#667eea"></uni-icons> |
| | | <text class="label-text">缓存库位号</text> |
| | | </view> |
| | | <view class="form-input-wrap"> |
| | | <input class="form-input" type="text" placeholder="扫码 / 输入缓存库位号" v-model="locNo" |
| | | :focus="locNoFocus" @input="locNoInput()" @focus="onLocNoFocus()" @blur="onLocNoBlur()" /> |
| | | <uni-icons v-if="locNo" type="clear" size="18" color="#c0c4cc" @click="clearLocNo"></uni-icons> |
| | | </view> |
| | | </view> |
| | | </view> |
| | | |
| | | <!-- 库位信息展示 --> |
| | | <view class="info-section" v-if="locCacheInfo"> |
| | | <view class="info-card"> |
| | | <view class="info-header"> |
| | | <text class="info-title">库位信息</text> |
| | | </view> |
| | | <view class="info-body"> |
| | | <view class="info-row"> |
| | | <view class="info-col"> |
| | | <text class="info-label">库位号</text> |
| | | <text class="info-value">{{locCacheInfo.locNo || '-'}}</text> |
| | | </view> |
| | | </view> |
| | | <view class="info-row"> |
| | | <view class="info-col half"> |
| | | <text class="info-label">排</text> |
| | | <text class="info-value">{{locCacheInfo.row1 || '-'}}</text> |
| | | </view> |
| | | <view class="info-col half"> |
| | | <text class="info-label">列</text> |
| | | <text class="info-value">{{locCacheInfo.bay1 || '-'}}</text> |
| | | </view> |
| | | </view> |
| | | <view class="info-row"> |
| | | <view class="info-col half"> |
| | | <text class="info-label">层</text> |
| | | <text class="info-value">{{locCacheInfo.lev1 || '-'}}</text> |
| | | </view> |
| | | <view class="info-col half"> |
| | | <text class="info-label">库位状态</text> |
| | | <text class="info-value" :class="{'locked': locCacheInfo.locSts === 'F', 'unlocked': locCacheInfo.locSts === 'O'}"> |
| | | {{getLocStsDesc(locCacheInfo.locSts)}} |
| | | </text> |
| | | </view> |
| | | </view> |
| | | </view> |
| | | </view> |
| | | </view> |
| | | |
| | | <!-- 底部操作按钮 --> |
| | | <view class="bottom-bar"> |
| | | <view class="btn-reset" @click="reset()"> |
| | | <uni-icons type="refresh" size="18" color="#909399"></uni-icons> |
| | | <text class="btn-text">重置</text> |
| | | </view> |
| | | <view class="btn-group"> |
| | | <view class="btn-unlock" :class="{'btn-disabled': !locCacheInfo || isSubmitting}" @click="unlockLoc()"> |
| | | <uni-icons type="unlocked" size="18" color="#ffffff"></uni-icons> |
| | | <text class="btn-text">确认已取走当前库位</text> |
| | | </view> |
| | | <view class="btn-lock" :class="{'btn-disabled': !locCacheInfo || isSubmitting}" @click="lockLoc()"> |
| | | <uni-icons type="locked" size="18" color="#ffffff"></uni-icons> |
| | | <text class="btn-text">标记为在库</text> |
| | | </view> |
| | | </view> |
| | | </view> |
| | | |
| | | <!-- 列操作按钮 --> |
| | | <view class="row-bar" v-if="locCacheInfo"> |
| | | <view class="btn-group-row"> |
| | | <view class="btn-unlock-row" :class="{'btn-disabled': isSubmitting}" @click="unlockBay()"> |
| | | <uni-icons type="unlocked" size="18" color="#ffffff"></uni-icons> |
| | | <text class="btn-text">确认已取走当前列</text> |
| | | </view> |
| | | <view class="btn-lock-row" :class="{'btn-disabled': isSubmitting}" @click="lockBay()"> |
| | | <uni-icons type="locked" size="18" color="#ffffff"></uni-icons> |
| | | <text class="btn-text">标记当前列在库</text> |
| | | </view> |
| | | </view> |
| | | </view> |
| | | |
| | | <!-- 排操作按钮 --> |
| | | <view class="row-bar" v-if="locCacheInfo" style="margin-top: 10px;"> |
| | | <view class="btn-group-row"> |
| | | <view class="btn-unlock-row" :class="{'btn-disabled': isSubmitting}" @click="clearAllColumnsInRow()"> |
| | | <uni-icons type="trash" size="18" color="#ffffff"></uni-icons> |
| | | <text class="btn-text">确认已取走当前排</text> |
| | | </view> |
| | | </view> |
| | | </view> |
| | | |
| | | <!-- 提示信息弹窗 --> |
| | | <uni-popup ref="message" type="message"> |
| | | <uni-popup-message :type="msgType" :message="messageText" :duration="2000"></uni-popup-message> |
| | | </uni-popup> |
| | | |
| | | <!-- 确认弹窗 --> |
| | | <uni-popup ref="confirmDialog" type="dialog"> |
| | | <uni-popup-dialog :type="msgType" cancelText="取消" confirmText="确认" :title="title" :content="content" |
| | | @confirm="confirmAction" @close="closeConfirm"></uni-popup-dialog> |
| | | </uni-popup> |
| | | |
| | | <!-- 选择满托/空托弹窗 --> |
| | | <uni-popup ref="fullPltDialog" type="dialog"> |
| | | <view class="popup-card"> |
| | | <view class="popup-header"> |
| | | <text class="popup-title">选择托盘类型</text> |
| | | </view> |
| | | <view class="popup-body"> |
| | | <view class="popup-row"> |
| | | <text class="popup-label">请选择托盘类型</text> |
| | | </view> |
| | | <view class="plt-options"> |
| | | <view class="plt-option" :class="{'selected': selectedFullPlt === true}" @click="selectFullPlt(true)"> |
| | | <uni-icons type="checkbox-filled" size="20" :color="selectedFullPlt === true ? '#667eea' : '#c0c4cc'"></uni-icons> |
| | | <text class="plt-text">满托</text> |
| | | </view> |
| | | <view class="plt-option" :class="{'selected': selectedFullPlt === false}" @click="selectFullPlt(false)"> |
| | | <uni-icons type="checkbox-filled" size="20" :color="selectedFullPlt === false ? '#667eea' : '#c0c4cc'"></uni-icons> |
| | | <text class="plt-text">空托</text> |
| | | </view> |
| | | </view> |
| | | </view> |
| | | <view class="popup-footer"> |
| | | <view class="popup-btn cancel" @click="closeFullPltDialog">取消</view> |
| | | <view class="popup-btn confirm" :class="{'disabled': selectedFullPlt === null}" @click="confirmFullPlt">确认</view> |
| | | </view> |
| | | </view> |
| | | </uni-popup> |
| | | </view> |
| | | </template> |
| | | |
| | | <script> |
| | | import rfidScanner from '@/common/rfid-scanner.js'; |
| | | |
| | | export default { |
| | | data() { |
| | | return { |
| | | baseUrl: '', |
| | | token: '', |
| | | locNo: '', |
| | | locNoFocus: true, |
| | | locCacheInfo: null, |
| | | msgType: 'success', |
| | | messageText: '', |
| | | title: '', |
| | | content: '', |
| | | isSubmitting: false, |
| | | actionType: '', // 'lock', 'unlock', 'lockBay', 'unlockBay' |
| | | actionLocNo: '', |
| | | selectedFullPlt: null // true-满托, false-空托, null-未选择 |
| | | } |
| | | }, |
| | | onLoad() { |
| | | |
| | | }, |
| | | onShow() { |
| | | this.baseUrl = uni.getStorageSync('baseUrl'); |
| | | this.token = uni.getStorageSync('token'); |
| | | // 设置当前页面实例,用于全局扫描时自动填入 |
| | | rfidScanner.setCurrentPageInstance(this); |
| | | }, |
| | | onHide() { |
| | | // 页面隐藏时停止RFID扫描 |
| | | }, |
| | | methods: { |
| | | // 库位号输入框获得焦点 |
| | | onLocNoFocus() { |
| | | console.log('[locCacheLock] 库位号输入框获得焦点'); |
| | | this.locNoFocus = true; |
| | | }, |
| | | // 库位号输入框失去焦点 |
| | | onLocNoBlur() { |
| | | console.log('[locCacheLock] 库位号输入框失去焦点'); |
| | | }, |
| | | clearLocNo() { |
| | | this.locNo = ''; |
| | | this.locCacheInfo = null; |
| | | this.locNoFocus = false; |
| | | setTimeout(() => { |
| | | this.locNoFocus = true; |
| | | }, 100); |
| | | }, |
| | | // 库位号输入事件 |
| | | locNoInput() { |
| | | setTimeout(() => { |
| | | if (this.locNo && this.locNo.length >= 6) { |
| | | this.queryLocCache(); |
| | | } |
| | | }, 300); |
| | | }, |
| | | // 查询库位信息 |
| | | queryLocCache() { |
| | | if (!this.locNo) { |
| | | return; |
| | | } |
| | | |
| | | let that = this; |
| | | uni.request({ |
| | | url: that.baseUrl + '/locCache/list/auth', |
| | | data: { |
| | | locNo: that.locNo, |
| | | curr: 1, |
| | | limit: 1 |
| | | }, |
| | | header: { |
| | | 'token': uni.getStorageSync('token') |
| | | }, |
| | | success(result) { |
| | | result = result.data; |
| | | if (result.code === 200 && result.data && result.data.records && result.data.records.length > 0) { |
| | | that.locCacheInfo = result.data.records[0]; |
| | | that.messageText = "查询成功"; |
| | | that.msgType = 'success'; |
| | | that.$refs.message.open(); |
| | | } else if (result.code == 403) { |
| | | that.messageText = result.msg; |
| | | that.msgType = 'error'; |
| | | that.$refs.message.open(); |
| | | setTimeout(() => { |
| | | uni.reLaunch({ |
| | | url: '../login/login' |
| | | }); |
| | | }, 1000); |
| | | } else { |
| | | that.locCacheInfo = null; |
| | | that.messageText = result.msg || "库位不存在"; |
| | | that.msgType = 'error'; |
| | | that.$refs.message.open(); |
| | | } |
| | | }, |
| | | fail: () => { |
| | | that.messageText = "网络请求超时"; |
| | | that.msgType = 'error'; |
| | | that.$refs.message.open(); |
| | | } |
| | | }); |
| | | }, |
| | | // 标记当前库位为在库 |
| | | lockLoc() { |
| | | if (!this.locCacheInfo || this.isSubmitting) return; |
| | | this.actionType = 'lock'; |
| | | this.actionLocNo = this.locNo; |
| | | this.selectedFullPlt = null; |
| | | this.$refs.fullPltDialog.open(); |
| | | }, |
| | | // 确认已取走当前库位 |
| | | unlockLoc() { |
| | | if (!this.locCacheInfo || this.isSubmitting) return; |
| | | this.actionType = 'unlock'; |
| | | this.actionLocNo = this.locNo; |
| | | this.title = '确认操作'; |
| | | this.content = '确认已取走库位:' + this.locNo + '?'; |
| | | this.$refs.confirmDialog.open(); |
| | | }, |
| | | // 标记当前列在库 |
| | | lockBay() { |
| | | if (!this.locCacheInfo || this.isSubmitting) return; |
| | | this.actionType = 'lockBay'; |
| | | this.actionLocNo = this.locNo; |
| | | this.selectedFullPlt = null; |
| | | this.$refs.fullPltDialog.open(); |
| | | }, |
| | | // 确认已取走当前列 |
| | | unlockBay() { |
| | | if (!this.locCacheInfo || this.isSubmitting) return; |
| | | this.actionType = 'unlockBay'; |
| | | this.actionLocNo = this.locNo; |
| | | this.title = '确认操作'; |
| | | this.content = '确认已取走第' + this.locCacheInfo.bay1 + '列的所有库位?'; |
| | | this.$refs.confirmDialog.open(); |
| | | }, |
| | | // 确认已取走当前排 |
| | | clearAllColumnsInRow() { |
| | | if (!this.locCacheInfo || this.isSubmitting) return; |
| | | this.actionType = 'clearAllColumnsInRow'; |
| | | this.actionLocNo = this.locNo; |
| | | this.title = '确认操作'; |
| | | this.content = '确认已取走第' + this.locCacheInfo.row1 + '排的所有库位(所有列)?'; |
| | | this.$refs.confirmDialog.open(); |
| | | }, |
| | | // 选择满托/空托 |
| | | selectFullPlt(fullPlt) { |
| | | this.selectedFullPlt = fullPlt; |
| | | }, |
| | | // 确认满托/空托选择 |
| | | confirmFullPlt() { |
| | | if (this.selectedFullPlt === null) return; |
| | | this.$refs.fullPltDialog.close(); |
| | | // 显示确认对话框 |
| | | if (this.actionType === 'lock') { |
| | | this.title = '确认标记'; |
| | | this.content = '确认将库位:' + this.actionLocNo + ' 标记为在库(' + (this.selectedFullPlt ? '满托' : '空托') + ')?'; |
| | | } else if (this.actionType === 'lockBay') { |
| | | this.title = '确认标记'; |
| | | this.content = '确认将第' + this.locCacheInfo.bay1 + '列的所有库位标记为在库(' + (this.selectedFullPlt ? '满托' : '空托') + ')?'; |
| | | } |
| | | this.$refs.confirmDialog.open(); |
| | | }, |
| | | // 关闭满托/空托选择弹窗 |
| | | closeFullPltDialog() { |
| | | this.$refs.fullPltDialog.close(); |
| | | this.selectedFullPlt = null; |
| | | }, |
| | | // 确认操作 |
| | | confirmAction() { |
| | | if (this.isSubmitting) return; |
| | | |
| | | this.isSubmitting = true; |
| | | let that = this; |
| | | let url = ''; |
| | | let data = {}; |
| | | |
| | | if (this.actionType === 'lock' || this.actionType === 'unlock') { |
| | | // 锁定/解锁单个库位 |
| | | url = that.baseUrl + '/locCache/lockOrUnlock/auth'; |
| | | data = { |
| | | locNo: that.actionLocNo, |
| | | lock: that.actionType === 'lock' |
| | | }; |
| | | // 如果是锁定操作,需要传递fullPlt参数 |
| | | if (that.actionType === 'lock') { |
| | | data.fullPlt = that.selectedFullPlt; |
| | | } |
| | | } else if (this.actionType === 'lockBay' || this.actionType === 'unlockBay') { |
| | | // 锁定/解锁当前列 |
| | | url = that.baseUrl + '/locCache/lockOrUnlockBay/auth'; |
| | | data = { |
| | | locNo: that.actionLocNo, |
| | | lock: that.actionType === 'lockBay' |
| | | }; |
| | | // 如果是锁定操作,需要传递fullPlt参数 |
| | | if (that.actionType === 'lockBay') { |
| | | data.fullPlt = that.selectedFullPlt; |
| | | } |
| | | } else if (this.actionType === 'clearAllColumnsInRow') { |
| | | // 清空整排(所有列) |
| | | url = that.baseUrl + '/locCache/clearAllColumnsInRow/auth'; |
| | | data = { |
| | | locNo: that.actionLocNo, |
| | | lock: false // 清空操作,lock=false |
| | | }; |
| | | } |
| | | |
| | | uni.request({ |
| | | url: url, |
| | | method: 'POST', |
| | | data: data, |
| | | header: { |
| | | 'token': uni.getStorageSync('token') |
| | | }, |
| | | success(result) { |
| | | var res = result.data; |
| | | if (res.code === 200) { |
| | | let actionDesc = ''; |
| | | if (that.actionType === 'lock') { |
| | | actionDesc = '标记为在库(' + (that.selectedFullPlt ? '满托' : '空托') + ')'; |
| | | } else if (that.actionType === 'unlock') { |
| | | actionDesc = '确认已取走当前库位'; |
| | | } else if (that.actionType === 'lockBay') { |
| | | actionDesc = '标记当前列在库(' + (that.selectedFullPlt ? '满托' : '空托') + ')'; |
| | | } else if (that.actionType === 'unlockBay') { |
| | | actionDesc = '确认已取走当前列'; |
| | | } else if (that.actionType === 'clearAllColumnsInRow') { |
| | | actionDesc = '确认已取走当前排'; |
| | | } |
| | | that.messageText = actionDesc + '成功'; |
| | | that.msgType = 'success'; |
| | | that.$refs.message.open(); |
| | | // 重新查询库位信息 |
| | | setTimeout(() => { |
| | | that.queryLocCache(); |
| | | }, 500); |
| | | // 重置选择 |
| | | that.selectedFullPlt = null; |
| | | } else if (res.code == 403) { |
| | | that.messageText = res.msg; |
| | | that.msgType = 'error'; |
| | | that.$refs.message.open(); |
| | | setTimeout(() => { |
| | | uni.reLaunch({ |
| | | url: '../login/login' |
| | | }); |
| | | }, 1000); |
| | | } else { |
| | | that.messageText = res.msg || "操作失败"; |
| | | that.msgType = 'error'; |
| | | that.$refs.message.open(); |
| | | } |
| | | }, |
| | | fail: () => { |
| | | that.messageText = "网络请求超时"; |
| | | that.msgType = 'error'; |
| | | that.$refs.message.open(); |
| | | }, |
| | | complete: () => { |
| | | that.isSubmitting = false; |
| | | that.$refs.confirmDialog.close(); |
| | | } |
| | | }); |
| | | }, |
| | | // 关闭确认弹窗 |
| | | closeConfirm() { |
| | | this.$refs.confirmDialog.close(); |
| | | }, |
| | | // 重置 |
| | | reset() { |
| | | this.locNo = ''; |
| | | this.locCacheInfo = null; |
| | | this.selectedFullPlt = null; |
| | | this.locNoFocus = false; |
| | | setTimeout(() => { |
| | | this.locNoFocus = true; |
| | | }, 100); |
| | | }, |
| | | // 获取库位状态描述 |
| | | getLocStsDesc(locSts) { |
| | | if (!locSts) return '未知'; |
| | | const statusMap = { |
| | | 'D': '空桶/空栈板', |
| | | 'F': '在库', |
| | | 'O': '空库位', |
| | | 'P': '拣料/盘点/并板出库中', |
| | | 'Q': '拣料/盘点/并板再入库', |
| | | 'R': '出库预约', |
| | | 'S': '入库预约', |
| | | 'X': '禁用', |
| | | 'Y': '被合并' |
| | | }; |
| | | return statusMap[locSts] || '未知'; |
| | | } |
| | | } |
| | | } |
| | | </script> |
| | | |
| | | <style> |
| | | /* 引入公共样式 */ |
| | | @import url('../../static/css/common.css'); |
| | | @import url('../../static/css/wms.css/wms.css'); |
| | | |
| | | .info-section { |
| | | padding: 20rpx; |
| | | } |
| | | |
| | | .info-card { |
| | | background: #ffffff; |
| | | border-radius: 16rpx; |
| | | box-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.08); |
| | | overflow: hidden; |
| | | } |
| | | |
| | | .info-header { |
| | | padding: 24rpx; |
| | | border-bottom: 1rpx solid #f0f0f0; |
| | | } |
| | | |
| | | .info-title { |
| | | font-size: 32rpx; |
| | | font-weight: 600; |
| | | color: #333333; |
| | | } |
| | | |
| | | .info-body { |
| | | padding: 24rpx; |
| | | } |
| | | |
| | | .info-row { |
| | | display: flex; |
| | | margin-bottom: 24rpx; |
| | | } |
| | | |
| | | .info-row:last-child { |
| | | margin-bottom: 0; |
| | | } |
| | | |
| | | .info-col { |
| | | flex: 1; |
| | | } |
| | | |
| | | .info-col.half { |
| | | flex: 0 0 50%; |
| | | } |
| | | |
| | | .info-label { |
| | | display: block; |
| | | font-size: 26rpx; |
| | | color: #999999; |
| | | margin-bottom: 8rpx; |
| | | } |
| | | |
| | | .info-value { |
| | | display: block; |
| | | font-size: 30rpx; |
| | | color: #333333; |
| | | font-weight: 500; |
| | | } |
| | | |
| | | .info-value.locked { |
| | | color: #f56c6c; |
| | | } |
| | | |
| | | .info-value.unlocked { |
| | | color: #67c23a; |
| | | } |
| | | |
| | | .btn-group { |
| | | display: flex; |
| | | flex: 1; |
| | | gap: 20rpx; |
| | | } |
| | | |
| | | .btn-unlock, .btn-lock { |
| | | flex: 1; |
| | | height: 88rpx; |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: center; |
| | | border-radius: 12rpx; |
| | | gap: 12rpx; |
| | | } |
| | | |
| | | .btn-unlock { |
| | | background: linear-gradient(135deg, #67c23a 0%, #85ce61 100%); |
| | | } |
| | | |
| | | .btn-lock { |
| | | background: linear-gradient(135deg, #f56c6c 0%, #f78989 100%); |
| | | } |
| | | |
| | | .btn-disabled { |
| | | opacity: 0.5; |
| | | pointer-events: none; |
| | | } |
| | | |
| | | .row-bar { |
| | | padding: 20rpx; |
| | | background: #f8f9fa; |
| | | border-top: 1rpx solid #e9ecef; |
| | | } |
| | | |
| | | .btn-group-row { |
| | | display: flex; |
| | | gap: 20rpx; |
| | | } |
| | | |
| | | .btn-unlock-row, .btn-lock-row { |
| | | flex: 1; |
| | | height: 88rpx; |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: center; |
| | | border-radius: 12rpx; |
| | | gap: 12rpx; |
| | | background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); |
| | | } |
| | | |
| | | .btn-unlock-row { |
| | | background: linear-gradient(135deg, #67c23a 0%, #85ce61 100%); |
| | | } |
| | | |
| | | .btn-lock-row { |
| | | background: linear-gradient(135deg, #f56c6c 0%, #f78989 100%); |
| | | } |
| | | |
| | | .plt-options { |
| | | display: flex; |
| | | gap: 20rpx; |
| | | margin-top: 20rpx; |
| | | } |
| | | |
| | | .plt-option { |
| | | flex: 1; |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: center; |
| | | gap: 12rpx; |
| | | padding: 24rpx; |
| | | border: 2rpx solid #e0e0e0; |
| | | border-radius: 12rpx; |
| | | background: #ffffff; |
| | | transition: all 0.3s; |
| | | } |
| | | |
| | | .plt-option.selected { |
| | | border-color: #667eea; |
| | | background: #f0f4ff; |
| | | } |
| | | |
| | | .plt-text { |
| | | font-size: 30rpx; |
| | | color: #333333; |
| | | font-weight: 500; |
| | | } |
| | | |
| | | .popup-btn.disabled { |
| | | opacity: 0.5; |
| | | pointer-events: none; |
| | | } |
| | | </style> |