|
|
<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"> <!-- 标签扫描输入框 --> <div class="input-group"> <el-input v-model="labelCode" placeholder="请扫描标签编码" class="form-input" clearable inputmode="none" autocomplete="off" autocorrect="off" spellcheck="false" @keyup.enter.native="handleLabelScan" ref="labelInput" /> </div>
<!-- 标签信息显示 (扫描后显示) --> <div v-if="labelInfo" class="info-section"> <div class="info-title"> <i class="el-icon-document">标签信息</i> <button class="print-btn" @click="handlePrint" :disabled="printLoading" > <i :class="printLoading ? 'el-icon-loading' : 'el-icon-printer'"></i> {{ printLoading ? '打印中...' : '打印' }} </button> </div>
<div class="info-row"> <span class="info-label">标签编码:</span> <span class="info-value">{{ labelInfo.unitId || '-' }}</span> </div>
<div class="info-row"> <span class="info-label">物料编码:</span> <span class="info-value">{{ labelInfo.partNo || '-' }}</span> </div>
<div class="info-row"> <span class="info-label">数量:</span> <span class="info-value">{{ labelInfo.qty || '0' }}</span> </div>
<div class="info-row"> <span class="info-label">批次号:</span> <span class="info-value">{{ labelInfo.batchNo || '-' }}</span> </div>
<div class="info-row"> <span class="info-label">仓库:</span> <span class="info-value">{{ labelInfo.warehouseId || '-' }}</span> </div>
<div class="info-row"> <span class="info-label">库位:</span> <span class="info-value">{{ labelInfo.locationId || '-' }}</span> </div>
<div class="info-row"> <span class="info-label">WDR:</span> <span class="info-value">{{ labelInfo.wdr || '-' }}</span> </div>
<div class="info-row"> <span class="info-label">engChgLevel:</span> <span class="info-value">{{ labelInfo.engChgLevel }}</span> </div>
<div class="info-row"> <span class="info-label">expiredDate:</span> <span class="info-value">{{ formatDate(labelInfo.expiredDate) }}</span> </div>
<div class="info-row"> <span class="info-label">创建时间:</span> <span class="info-value">{{ formatDate(labelInfo.createdDate) }}</span> </div>
<!-- 预留申请单号 - rqrq --> <div class="info-row" v-if="labelInfo.reserveOrderRef1"> <span class="info-label">预留申请单号:</span> <span class="info-value">{{ labelInfo.reserveOrderRef1 || '-' }}</span> </div>
<!-- 预留订单号 - rqrq --> <div class="info-row" v-if="labelInfo.reserveOrderRef3"> <span class="info-label">预留订单号:</span> <span class="info-value">{{ labelInfo.reserveOrderRef3 || '-' }}</span> </div> </div>
<!-- 底部操作按钮 --> <div v-if="labelInfo" class="bottom-actions"> <button class="action-btn primary" @click="showSplitDialog" > 拆分 </button> <button class="action-btn secondary" @click="clearData" > 清空 </button> </div> </div> </div> </div> <!-- 拆分对话框 --> <el-dialog title="标签拆分" :visible.sync="splitDialogVisible" width="90%" :close-on-click-modal="false" :append-to-body="true" :modal-append-to-body="true" > <div class="split-dialog-content"> <div class="split-info-row"> <span class="split-label">原标签编码:</span> <span class="split-value">{{ labelInfo ? labelInfo.unitId : '' }}</span> </div> <div class="split-info-row"> <span class="split-label">当前数量:</span> <span class="split-value">{{ labelInfo ? labelInfo.qty : 0 }}</span> </div> <div class="split-input-group"> <label class="split-label required">拆分数量:</label> <el-input v-model="splitQty" type="number" placeholder="请输入拆分数量(必须小于100)" class="split-input" ref="splitInput" /> <div class="split-hint" v-if="splitQty && !isValidSplitQty"> <i class="el-icon-warning"></i> 拆分数量必须大于0且小于当前数量 </div> </div> <div class="split-info-row"> <span class="split-label">拆分后原标签剩余:</span> <span class="split-value split-remain">{{ calculateRemainQty }}</span> </div> </div> <div slot="footer" class="dialog-footer"> <button class="dialog-btn cancel" @click="splitDialogVisible = false"> 取消 </button> <button class="dialog-btn confirm" @click="confirmSplit" :disabled="splitLoading || !isValidSplitQty" > {{ splitLoading ? '处理中...' : '确定拆分' }} </button> </div> </el-dialog> </div></template>
<script>import { queryLabelInfo, splitLabel } from '@/api/inventory/label'import { printLabelCommon } from '@/api/production/production-inbound.js'
export default { name: 'LabelQuery',
data() { return { site: localStorage.getItem('site'), labelCode: '', labelInfo: null, loading: false, printLoading: false, splitDialogVisible: false, splitQty: '', splitLoading: false }; }, computed: { /** * 计算拆分后原标签剩余数量 */ calculateRemainQty() { if (!this.labelInfo || !this.splitQty) { return this.labelInfo ? this.labelInfo.qty : 0; } const currentQty = parseFloat(this.labelInfo.qty) || 0; const split = parseFloat(this.splitQty) || 0; const remain = currentQty - split; return remain >= 0 ? remain : 0; }, /** * 验证拆分数量是否有效 */ isValidSplitQty() { if (!this.splitQty || !this.labelInfo) { return false; } const split = parseFloat(this.splitQty); const current = parseFloat(this.labelInfo.qty) || 0; return split > 0 && split < current; } },
methods: { /** * 返回上一页 */ handleBack() { this.$router.back(); },
/** * 处理标签扫描 */ handleLabelScan() { if (!this.labelCode.trim()) { this.$message.error('请扫描有效的标签编码'); return; }
this.loading = true;
queryLabelInfo({ site: this.site, labelCode: this.labelCode.trim() }).then(({ data }) => { this.loading = false;
if (data && data.code === 0) { this.labelInfo = data.data; this.$message.success('查询成功'); } else { this.$message.error(data.msg || '标签不存在'); this.labelCode = ''; this.labelInfo = null; this.focusLabelInput(); } }).catch(error => { this.loading = false; console.error('查询标签失败:', error); this.$message.error('查询异常'); this.labelCode = ''; this.labelInfo = null; this.focusLabelInput(); }); },
/** * 清空数据 */ clearData() { this.labelCode = ''; this.labelInfo = null; this.focusLabelInput(); },
/** * 聚焦标签输入框 */ focusLabelInput() { this.$nextTick(() => { if (this.$refs.labelInput) { this.$refs.labelInput.focus(); } }); },
/** * 格式化日期 */ formatDate(date) { if (!date) return '-';
const d = new Date(date); const year = d.getFullYear(); const month = String(d.getMonth() + 1).padStart(2, '0'); const day = String(d.getDate()).padStart(2, '0'); const hours = String(d.getHours()).padStart(2, '0'); const minutes = String(d.getMinutes()).padStart(2, '0');
return `${year}-${month}-${day} ${hours}:${minutes}`; },
/** * 获取状态标签类型 */ getStatusType(inStockFlag) { return inStockFlag === 'Y' ? 'success' : 'danger'; },
/** * 处理打印 */ handlePrint() { if (!this.labelInfo || !this.labelInfo.unitId) { this.$message.error('没有可打印的标签信息'); return; } let printLabelType; if (this.labelInfo.partNo && this.labelInfo.partNo.startsWith("80")) { printLabelType = '库存成品标签'; } else { printLabelType = 'BIL标签'; } // 调用打印方法,传入unitId数组和标签类型
this.printViaServer([this.labelInfo.unitId], printLabelType); },
/** * 通过服务器打印 * @param {Array} unitIds - HU unitId列表 * @param {String} printLabelType - 标签类型 */ async printViaServer(unitIds, printLabelType) { if (!unitIds || unitIds.length === 0) { console.warn('没有可打印的标签'); return; }
this.printLoading = true;
try { const printRequest = { userId: localStorage.getItem('userName'), username: localStorage.getItem('userName'), site: localStorage.getItem('site'), unitIds: unitIds, labelType: printLabelType }; console.log('打印请求:', printRequest);
const { data } = await printLabelCommon(printRequest);
if (data.code === 200 || data.code === 0) { this.$message.success(`打印任务已发送!`); } else { this.$message.error(data.msg || '打印失败'); } } catch (error) { console.error('服务器打印失败:', error); this.$message.error(`打印失败: ${error.message || error}`); } finally { this.printLoading = false; } }, /** * 显示拆分对话框 */ showSplitDialog() { if (!this.labelInfo) { this.$message.error('没有可拆分的标签'); return; } this.splitQty = ''; this.splitDialogVisible = true; // 聚焦到拆分数量输入框
this.$nextTick(() => { if (this.$refs.splitInput) { this.$refs.splitInput.focus(); } }); }, /** * 确认拆分 */ async confirmSplit() { // 验证拆分数量
if (!this.splitQty) { this.$message.error('请输入拆分数量'); return; } const splitQty = parseFloat(this.splitQty); const currentQty = parseFloat(this.labelInfo.qty); if (splitQty <= 0) { this.$message.error('拆分数量必须大于0'); return; } if (splitQty >= currentQty) { this.$message.error('拆分数量必须小于当前数量'); return; } this.splitLoading = true; try { const { data } = await splitLabel({ site: this.site, unitId: this.labelInfo.unitId, splitQty: splitQty, operatorName: localStorage.getItem('userName') }); if (data && data.code === 0) { const result = data.data; this.$message.success('拆分成功!'); // 关闭对话框
this.splitDialogVisible = false; // 确定标签类型
let printLabelType; if (this.labelInfo.partNo && this.labelInfo.partNo.startsWith("80")) { printLabelType = '库存成品标签'; } else { printLabelType = 'BIL标签'; } // 打印原标签和新标签
console.log('打印标签:', [result.originalUnitId, result.newUnitId]); await this.printViaServer([result.originalUnitId, result.newUnitId], printLabelType); // 刷新标签信息(显示更新后的数量)
this.labelCode = this.labelInfo.unitId; this.handleLabelScan(); } else { this.$message.error(data.msg || '拆分失败'); } } catch (error) { console.error('拆分标签失败:', error); this.$message.error('拆分异常: ' + (error.message || error)); } finally { this.splitLoading = false; } } },
mounted() { // 页面加载后自动聚焦标签输入框
this.focusLabelInput(); }};</script>
<style scoped>.input-group { margin-bottom: 1px !important;}
/* PDA容器样式 */.pda-container { width: 100vw; height: 120vh; display: flex; flex-direction: column; background: #f5f5f5; font-family: 'Arial', sans-serif;}
/* 头部栏样式 */.header-bar { display: flex; justify-content: space-between; align-items: center; padding: 8px 16px; background: #17B3A3; color: white; height: 40px; min-height: 40px; max-height: 40px;}
.header-left { display: flex; align-items: center; cursor: pointer;}
.header-left i { margin-right: 8px; font-size: 18px;}
.header-left span { font-size: 16px; font-weight: 500;}
.header-right { cursor: pointer; font-size: 14px; padding: 4px 8px; border-radius: 4px;}
/* 主要内容区 */.table-body { flex: 1; overflow-y: auto;}
.main-content { padding: 16px;}
/* 输入组样式 */
.input-label { display: block; margin-bottom: 8px; font-size: 14px; font-weight: 500; color: #333;}
.form-input { width: 100%; height: 44px;}
/* 信息展示区 */.info-section { background: white; border-radius: 8px; padding: 16px; box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);}
.info-title { display: flex; align-items: center; justify-content: space-between; font-size: 16px; font-weight: bold; color: #17B3A3; margin-bottom: 6px; padding-bottom: 5px; border-bottom: 2px solid #17B3A3;}
.info-title i { margin-right: 8px; font-size: 18px;}
/* 打印按钮 */.print-btn { display: flex; align-items: center; gap: 4px; padding: 6px 12px; background: #17B3A3; color: white; border: none; border-radius: 4px; font-size: 14px; cursor: pointer; transition: all 0.2s; white-space: nowrap;}
.print-btn:hover:not(:disabled) { background: #15a394; transform: translateY(-1px); box-shadow: 0 2px 8px rgba(23, 179, 163, 0.3);}
.print-btn:active:not(:disabled) { transform: translateY(0);}
.print-btn:disabled { background: #ccc; cursor: not-allowed; opacity: 0.6;}
.print-btn i { margin-right: 0; font-size: 16px;}
.info-row { display: flex; justify-content: space-between; align-items: flex-start; padding: 10px 0; border-bottom: 1px solid #f0f0f0;}
.info-row:last-child { border-bottom: none;}
.info-label { font-size: 14px; color: #666; min-width: 90px; flex-shrink: 0;}
.info-value { font-size: 14px; font-weight: 500; color: #333; flex: 1; text-align: right; word-break: break-all;}
/* 底部按钮区 */.bottom-actions { display: flex; gap: 12px; padding-top: 16px;}
.action-btn { flex: 1; padding: 12px 24px; border: none; border-radius: 6px; font-size: 16px; font-weight: 500; cursor: pointer; transition: all 0.2s; min-height: 44px;}
.action-btn.primary { background: #17B3A3; color: white;}
.action-btn.primary:hover { background: #15a394;}
.action-btn.primary:disabled { background: #ccc; cursor: not-allowed;}
.action-btn.secondary { background: #f5f5f5; color: #333; border: 1px solid #ddd;}
.action-btn.secondary:hover { background: #e8e8e8;}
/* 拆分对话框样式 */.split-dialog-content { padding: 16px 0;}
.split-info-row { display: flex; justify-content: space-between; align-items: center; padding: 12px 0; border-bottom: 1px solid #f0f0f0;}
.split-label { font-size: 14px; color: #666; font-weight: 500;}
.split-value { font-size: 15px; font-weight: 600; color: #333;}
.split-value.split-remain { color: #17B3A3; font-size: 16px;}
.split-input-group { margin: 20px 0;}
.split-input-group .split-label { display: block; margin-bottom: 8px;}
.split-input { width: 100%;}
/* 对话框底部按钮 */.dialog-footer { display: flex; gap: 12px; padding-top: 16px;}
.dialog-btn { flex: 1; padding: 12px 24px; border: none; border-radius: 6px; font-size: 16px; font-weight: 500; cursor: pointer; transition: all 0.2s; min-height: 44px;}
.dialog-btn.confirm { background: #17B3A3; color: white;}
.dialog-btn.confirm:hover:not(:disabled) { background: #15a394;}
.dialog-btn.confirm:disabled { background: #ccc; cursor: not-allowed; opacity: 0.6;}
.dialog-btn.cancel { background: #f5f5f5; color: #333; border: 1px solid #ddd;}
.dialog-btn.cancel:hover { background: #e8e8e8;}
/* 强制对话框显示在最上层 */::v-deep .el-dialog__wrapper { z-index: 9999 !important;}
::v-deep .el-dialog { z-index: 10000 !important;}
::v-deep .v-modal { z-index: 9998 !important;}
/* 响应式设计 */@media screen and (max-width: 480px) { .header-bar { padding: 8px 12px; }
.main-content { padding: 12px; }
.info-section { padding: 2px; }
.info-label { font-size: 13px; min-width: 80px; }
.info-value { font-size: 13px; }
.action-btn { padding: 10px 16px; font-size: 14px; }}</style>
|