|
|
<template> <div> <div class="pda-container"> <!-- 头部栏 --> <div class="header-bar"> <div class="header-left" @click="handleBack"> <i class="el-icon-arrow-left"></i> <span>查看托盘</span> </div> <div class="header-right" @click="$router.push({ path: '/' })"> 首页 </div> </div> <div class="table-body" style="max-height: 500px; overflow-y: auto;"> <div class="main-content form-section"> <!-- 栈板扫描 - rqrq --> <div class="input-group"> <label class="input-label">栈板编码</label> <el-input v-model="palletCode" placeholder="请扫描栈板编码" class="form-input" clearable @keyup.enter.native="handlePalletScan" ref="palletInput" /> </div>
<!-- 筛选条件 (扫描栈板后显示) - rqrq --> <div v-if="palletScanned" class="input-group"> <label class="input-label">位置</label> <div style="display: flex; gap: 8px;"> <el-select v-model="selectedPosition" placeholder="请选择位置" style="flex: 0.75;" > <el-option label="ALL" value=""></el-option> <el-option v-for="position in positionOptions" :key="position" :label="position" :value="position" /> </el-select> <button class="action-btn secondary" style="flex: 0.25; margin: 0; white-space: nowrap;" @click="refreshTable" > 刷新 </button> </div> </div> </div>
<!-- 栈板明细表格 (扫描栈板后显示) - rqrq --> <div v-if="palletScanned" class="rma-list"> <div class="list-title-row" style="display: flex; gap: 8px; align-items: center; padding: 0;"> <div class="list-title" style="flex: 1; margin: 0; display: flex; align-items: center; flex-wrap: wrap; gap: 5px;"> <button class="action-btn primary" style="margin: 0;" @click="showDetailModal" > {{ '浏览明细' }} </button> <label style="margin-left: 5px;">条码数:{{detailList.length}}</label> <!-- 预定清单按钮 - rqrq --> <button class="action-btn" :class="reserveCount > 0 ? 'warning' : 'secondary'" style="margin: 0; margin-left: 10px;" @click="showReserveModal"> 预定清单({{ reserveCount }}) </button> </div> </div> <div class="detail-table"> <div class="table-header"> <div class="col-position">位置</div> <div class="col-layer">层数</div> <div class="col-serial">标签号</div> </div> <div v-for="(detail, index) in detailList" :key="index" class="table-row" > <div class="col-position">{{ detail.position }}</div> <div class="col-layer">{{ detail.layer }}</div> <div class="col-serial">{{ detail.serialNo }}</div> </div> <!-- 暂无数据提示 --> <div v-if="detailList.length === 0" class="table-row empty-row"> <div class="empty-hint">暂无栈板明细数据</div> </div> </div> </div> </div> </div> <!-- 浏览明细弹窗 - rqrq --> <el-dialog :title="'栈板明细 (共'+detailList.length+'条)'" :visible.sync="detailModalVisible" width="90%" :close-on-click-modal="false" :show-close="false" :modal="true" :modal-append-to-body="true" :append-to-body="true" > <div class="table-body" style="max-height: 400px; overflow-y: auto;"> <div class="detail-table"> <div class="table-header"> <div class="col-position">位置</div> <div class="col-layer">层数</div> <div class="col-serial">标签号</div> </div> <div v-for="(detail, index) in detailList" :key="index" class="table-row" > <div class="col-position">{{ detail.position }}</div> <div class="col-layer">{{ detail.layer }}</div> <div class="col-serial">{{ detail.serialNo }}</div> </div> <!-- 暂无数据提示 --> <div v-if="detailList.length === 0" class="table-row empty-row"> <div class="empty-hint">暂无栈板明细数据</div> </div> </div> </div> <div slot="footer" class="dialog-footer"> <button class="action-btn secondary" @click="detailModalVisible=false">关闭</button> </div> </el-dialog>
<!-- 预定清单弹窗 - rqrq --> <el-dialog :title="'预定清单 (共'+reserveCount+'条)'" :visible.sync="reserveModalVisible" width="95%" :close-on-click-modal="false" :show-close="false" :modal="true" :modal-append-to-body="true" :append-to-body="true" > <div class="table-body" style="max-height: 350px; overflow-y: auto;"> <div class="detail-table"> <div class="table-header reserve-header"> <div class="col-serial-reserve">标签号</div> <div class="col-ref">申请单号</div> <div class="col-ref">订单号</div> </div> <div v-for="(item, index) in reservedLabels" :key="index" class="table-row" > <div class="col-serial-reserve">{{ item.serialNo || '-' }}</div> <div class="col-ref">{{ item.reserveOrderRef1 || '-' }}</div> <div class="col-ref">{{ item.reserveOrderRef3 || '-' }}</div> </div> <!-- 暂无数据提示 --> <div v-if="reservedLabels.length === 0" class="table-row empty-row"> <div class="empty-hint">暂无预定标签</div> </div> </div> </div> <div slot="footer" class="dialog-footer" style="display: flex; gap: 10px; justify-content: center;"> <button class="action-btn secondary" @click="reserveModalVisible=false" :disabled="cancelReserveLoading">关闭</button> <button class="action-btn danger" @click="handleBatchCancelReserve" :disabled="cancelReserveLoading || reservedLabels.length === 0 || errorStationFlag" v-if="reservedLabels.length > 0" > {{ cancelReserveLoading ? '取消中...' : '一键取消预定' }} </button> </div> <!-- 异常位提示:以后端 errorStationFlag 为准,不再写死 1101 - rqrq --> <div v-if="errorStationFlag" class="reserve-warning"> <i class="el-icon-warning"></i> 栈板在立库异常位上,不允许取消预定 </div> </el-dialog> </div></template>
<script>import { getPalletInfoSimple, getPalletDetails, getPalletReservedLabels, batchCancelReserve} from '../../../api/haianAutoWarehouse/palletPacking'
export default { name: 'haianPalletSearch', data() { return { site: this.$store.state.user.site, palletCode: '', palletScanned: false, detailModalVisible: false,
// 筛选条件 - rqrq
selectedPosition: '', positionOptions: [],
// 栈板明细 - rqrq
detailList: [],
// 栈板库位 - rqrq
locationCode: '', // 是否异常位:由后端 ERROR_STATIONS 判定,禁止前端写死 1101 - rqrq
errorStationFlag: false,
// 预定清单相关 - rqrq
reserveModalVisible: false, reservedLabels: [], reserveCount: 0, cancelReserveLoading: false }; }, methods: { // 返回上一页 - rqrq
handleBack() { // 返回菜单前清空托盘查询状态,避免keep-alive缓存导致数据残留 - rqrq
this.resetPage(false) this.$router.back(); },
// 重置页面到初始状态 - rqrq
resetPage(needFocus = true) { this.site = this.$store.state.user.site; this.palletCode = ''; this.palletScanned = false; this.selectedPosition = ''; this.positionOptions = []; this.detailList = []; this.detailModalVisible = false; this.locationCode = ''; this.reserveModalVisible = false; this.reservedLabels = []; this.reserveCount = 0; this.cancelReserveLoading = false;
// 聚焦到栈板输入框 - rqrq
if (needFocus) { this.$nextTick(() => { if (this.$refs.palletInput) { this.$refs.palletInput.focus(); } }); } },
// 扫描栈板(使用无校验的简单查询)- rqrq
handlePalletScan() { if (!this.site) { this.$alert('当前用户缺少site,无法执行海安托盘查询', '提示', { confirmButtonText: '确定' }); return; } if (!this.palletCode.trim()) { this.$alert('请输入栈板编码', '提示', { confirmButtonText: '确定' }); return; }
getPalletInfoSimple({ site: this.site, palletId: this.palletCode }).then(({ data }) => { if (data.code === 0) { this.palletCode = data.palletId; this.palletScanned = true; this.positionOptions = data.positions || []; this.locationCode = data.locationCode || ''; this.refreshTable(); this.loadReservedLabels(); // 加载预定标签数量 - rqrq
} else { let errorMsg = data.msg || '栈板不存在'; if (errorMsg.length > 100) { errorMsg = errorMsg.substring(0, 100) + '...'; } this.$alert(errorMsg, '错误', { confirmButtonText: '确定', callback: () => { this.palletCode = ''; this.$nextTick(() => { if (this.$refs.palletInput) { this.$refs.palletInput.focus(); } }); } }); } }).catch(error => { console.error('查询栈板失败:', error); let errorMsg = error.message || '查询栈板失败'; if (errorMsg.length > 100) { errorMsg = errorMsg.substring(0, 100) + '...'; } this.$alert(errorMsg, '错误', { confirmButtonText: '确定', callback: () => { this.palletCode = ''; this.$nextTick(() => { if (this.$refs.palletInput) { this.$refs.palletInput.focus(); } }); } }); }); },
// 刷新表格 - rqrq
refreshTable() { getPalletDetails({ site: this.site, palletId: this.palletCode, position: this.selectedPosition, layer: '' }).then(({ data }) => { if (data.code === 0) { this.detailList = data.details || []; } else { this.detailList = []; } }).catch(error => { console.error('获取栈板明细失败:', error); this.detailList = []; }); },
// 显示明细弹窗 - rqrq
showDetailModal() { this.detailModalVisible = true; },
// 显示预定清单弹窗 - rqrq
showReserveModal() { this.loadReservedLabels(); this.reserveModalVisible = true; },
// 加载预定标签列表 - rqrq
loadReservedLabels() { getPalletReservedLabels({ site: this.site, palletId: this.palletCode }).then(({ data }) => { if (data.code === 0 && data.data) { this.reservedLabels = data.data.reservedLabels || []; this.reserveCount = data.data.reserveCount || 0; this.locationCode = data.data.locationCode || ''; this.errorStationFlag = data.data.errorStationFlag === true; } else { this.reservedLabels = []; this.reserveCount = 0; this.errorStationFlag = false; } }).catch(error => { console.error('获取预定标签列表失败:', error); this.reservedLabels = []; this.reserveCount = 0; this.errorStationFlag = false; }); },
// 一键取消预定 - rqrq
handleBatchCancelReserve() { if (this.errorStationFlag) { this.$alert('栈板在立库异常位上,不允许取消预定', '错误', { confirmButtonText: '确定' }); return; }
this.$confirm('确定要取消所有预定标签吗?', '提示', { confirmButtonText: '确定', cancelButtonText: '取消', type: 'warning' }).then(() => { this.doBatchCancelReserve(); }).catch(() => { // 用户取消
}); },
// 执行批量取消预定 - rqrq
doBatchCancelReserve() { this.cancelReserveLoading = true;
batchCancelReserve({ site: this.site, palletId: this.palletCode }).then(({ data }) => { if (data.code === 0) { this.$message.success('取消预定成功'); this.reserveModalVisible = false; // 重新加载预定标签列表 - rqrq
this.loadReservedLabels(); } else { this.$alert(data.msg || '取消预定失败', '错误', { confirmButtonText: '确定' }); } }).catch(error => { console.error('批量取消预定失败:', error); this.$alert('取消预定异常', '错误', { confirmButtonText: '确定' }); }).finally(() => { this.cancelReserveLoading = false; }); } }, // keep-alive页面每次激活统一重置,保证海安“退出再进入”无历史残留 - rqrq
activated() { this.resetPage(true); }, // 离开页面时主动清理缓存状态,避免下次进入展示旧查询结果 - rqrq
beforeRouteLeave(to, from, next) { this.resetPage(false); next(); }, mounted() { this.resetPage(true); }};</script>
<style scoped>/* 表格样式 */.detail-table { background: white; border-radius: 6px; overflow: hidden; border: 1px solid #e0e0e0;}
.table-header,.table-row { display: flex; align-items: center; padding: 8px; border-bottom: 1px solid #e0e0e0;}
.table-header { background: #f5f5f5; font-weight: bold; font-size: 14px;}
.table-row { font-size: 13px;}
.table-row:last-child { border-bottom: none;}
.col-position { flex: 1; text-align: center;}
.col-layer { flex: 1; text-align: center;}
.col-serial { flex: 4; text-align: center; word-break: break-all;}
/* 空数据提示 */.empty-hint { text-align: center; color: #999; padding: 20px; background: white; border-radius: 6px; margin-top: 16px;}
/* 模态框样式 */.scan-modal-content { padding: 10px 0;}
.modal-form { margin-bottom: 16px;}
.dialog-footer { text-align: center;}
/* 修复模态框层级问题 */::v-deep .el-dialog__wrapper { z-index: 2000 !important;}
::v-deep .el-overlay { z-index: 2000 !important;}
/* 修复单选框样式 */::v-deep .el-radio { margin-right: 8px !important;}
::v-deep .el-radio__label { font-size: 14px;}
/* 标题行样式 */.list-title-row { display: flex; justify-content: space-between; align-items: center; margin-bottom: 8px;}
.list-title-row .list-title { margin: 0; flex: 1;}
/* 空数据行样式 */.empty-row { justify-content: center; align-items: center; padding: 20px; border-bottom: none;}
.empty-row .empty-hint { text-align: center; color: #999; width: 100%;}
/* 预定清单相关样式 - rqrq */.action-btn.warning { background: #E6A23C; color: white; border: none;}
.action-btn.warning:hover { background: #d99429;}
.action-btn.danger { background: #F56C6C; color: white; border: none;}
.action-btn.danger:hover:not(:disabled) { background: #e45656;}
.action-btn.danger:disabled { background: #ccc; cursor: not-allowed; opacity: 0.6;}
.reserve-header { font-size: 12px;}
.col-serial-reserve { flex: 2; text-align: center; word-break: break-all; font-size: 12px;}
.col-ref { flex: 1.5; text-align: center; word-break: break-all; font-size: 12px;}
.reserve-warning { text-align: center; color: #E6A23C; padding: 10px; font-size: 14px; background: #fdf6ec; border-radius: 4px; margin-top: 10px;}
.reserve-warning i { margin-right: 5px;}
</style>
|