|
|
<template> <div> <div class="pda-container"> <div class="status-bar"> <div class="goBack" @click="$router.back()"><i class="el-icon-arrow-left"></i>上一页</div> <div class="goBack">其它出库</div> <div class="network" style="color: #fff" @click="$router.push({ path: '/' })">🏠首页</div> </div> <div style="overflow-y: auto"> <!-- 搜索框 --> <div class="search-container"> <el-input clearable class="compact-input" v-model="scanCode" placeholder="请扫描HandlingUnit条码" prefix-icon="el-icon-search" @keyup.enter.native="handleScan" ref="scanInput" /> <div class="mode-switch"> <el-switch class="custom-switch" v-model="isRemoveMode" active-color="#ff4949" inactive-color="#13ce66"> </el-switch> <span v-if="isRemoveMode" class="switch-text">{{ '移除' }}</span> <span v-else class="switch-text2">{{ '添加' }}</span> </div> </div>
<!-- 其它出库信息卡片 --> <div class="material-info-card"> <div class="input-form"> <div class="form-row"> <div class="form-item"> <label class="form-label">操作员</label> <el-input v-model="outboundForm.operatorName" placeholder="请输入操作员" size="small"> </el-input> </div> <div class="form-item"> <label class="form-label">操作时间</label> <el-date-picker v-model="outboundForm.operateTime" type="datetime" placeholder="选择操作时间" size="small" format="yyyy-MM-dd HH:mm:ss" value-format="yyyy-MM-dd HH:mm:ss"> </el-date-picker> </div> </div>
<div class="form-row"> <div class="form-item full-width"> <label class="form-label">出库原因</label> <el-input v-model="outboundForm.outboundReason" placeholder="请输入出库原因" size="small"> </el-input> </div> </div> </div> </div>
<!-- 其它出库信息确认标题 --> <div class="section-title"> <div class="title-left"> <i class="el-icon-box"></i> <span>其它出库信息确认</span> </div> </div>
<!-- 扫描的HandlingUnit明细列表 --> <div class="scanned-items" v-if="scannedItems.length > 0" style="margin: 2px;"> <div class="label-list"> <el-form label-position="top" style="margin: 3px;"> <el-row :gutter="5" v-for="(label, index) in scannedItems" :key="label.id" :class="index < scannedItems.length - 1 ? 'bottom-line-row' : ''" style="border: 1px solid #e0e0e0; border-radius: 4px; margin-bottom: 8px; padding: 8px;"> <el-col :span="12"> <el-form-item label="HandlingUnit"> <span>{{ label.unitId }}</span> </el-form-item> </el-col> <el-col :span="8"> <el-form-item label="物料编码"> <span>{{ label.partNo }}</span> </el-form-item> </el-col> <el-col :span="4"> <el-form-item label="数量"> <span>{{ label.qty }} {{ label.unit || '个' }}</span> </el-form-item> </el-col> <el-col :span="24" v-if="label.partDesc"> <el-form-item label="物料描述"> <span>{{ label.partDesc }}</span> </el-form-item> </el-col> <el-col :span="12" v-if="label.batchNo"> <el-form-item label="批次号"> <span>{{ label.batchNo }}</span> </el-form-item> </el-col> <el-col :span="12" v-if="label.locationId"> <el-form-item label="库位"> <span>{{ label.locationId }}</span> </el-form-item> </el-col> <el-col :span="24"> <div class="action-buttons" style="text-align: right; margin-top: 8px;"> <el-button size="mini" type="danger" @click="removeLabel(label)">删除</el-button> </div> </el-col> </el-row> </el-form> </div> </div>
<!-- 空状态 --> <div v-if="scannedItems.length === 0" class="empty-labels"> <div style="text-align: center; padding: 20px;"> <p style="color: #999; margin: 0;">暂无扫描HandlingUnit</p> </div> </div>
<!-- 底部操作按钮 --> <div class="bottom-actions" v-if="scannedItems.length > 0"> <button class="action-btn primary" @click="confirmOutbound"> 确认其它出库 </button> <button class="action-btn secondary" style="margin-left: 10px;" @click="cancelProcess"> 取消 </button> </div> </div> </div> </div></template>
<script>import { scanHandlingUnitLabel, confirmOtherOutbound, getOtherOutboundHistory } from '@/api/po/po'
export default { name: 'OtherOutbound', data() { return { scanCode: '', isRemoveMode: false, // 默认为添加模式
outboundForm: { operatorName: '', operateTime: '', outboundReason: '' }, scannedItems: [], site: localStorage.getItem('site') || 'SITE01' }; }, methods: { // 处理扫描
handleScan() { if (!this.scanCode.trim()) { return; }
if (this.isRemoveMode) { this.removeLabelByCode(this.scanCode.trim()); } else { this.validateAndAddLabel(this.scanCode.trim()); } this.scanCode = ''; },
// 验证标签并添加到列表
validateAndAddLabel(unitId) { const params = { unitId: unitId, site: this.site, };
scanHandlingUnitLabel(params).then(({ data }) => { if (data && data.code === 0 && data.data) { const huInfo = data.data; this.processHandlingUnit(unitId, huInfo); } else { this.$message.error(data.msg || 'HandlingUnit不存在或查询失败'); } }).catch(error => { this.$message.error('扫描失败'); }); },
// 处理HandlingUnit数据
processHandlingUnit(unitId, huInfo) { // 检查是否已经扫描过
const exists = this.scannedItems.find(item => item.unitId === unitId); if (exists) { this.$message.warning('该HandlingUnit已扫描,请勿重复扫描'); return; }
// 校验HU是否属于当前站点
if (huInfo.site && huInfo.site !== this.site) { this.$message.error('HandlingUnit站点不匹配'); return; }
// 校验HU是否在库
if (huInfo.inStockFlag !== 'Y') { this.$message.error('HandlingUnit不在库,无法出库'); return; }
// 添加到列表
this.scannedItems.push({ id: Date.now(), unitId: unitId, partNo: huInfo.partNo, partDesc: huInfo.partDesc, qty: huInfo.qty, unit: huInfo.unit, batchNo: huInfo.batchNo, locationId: huInfo.locationId });
this.$message.success('扫描成功'); },
// 根据扫描码移除标签
removeLabelByCode(unitId) { const index = this.scannedItems.findIndex(item => item.unitId === unitId); if (index > -1) { this.scannedItems.splice(index, 1); this.$message.success('移除成功'); } else { this.$message.warning('未找到该HandlingUnit'); } },
// 删除标签
removeLabel(label) { const index = this.scannedItems.indexOf(label); if (index > -1) { this.scannedItems.splice(index, 1); this.$message.success('删除成功'); } },
// 确认其它出库
confirmOutbound() { // 验证必填字段
if (!this.outboundForm.operatorName) { this.$message.error('请输入操作员'); return; }
if (!this.outboundForm.operateTime) { this.$message.error('请选择操作时间'); return; }
if (this.scannedItems.length === 0) { this.$message.error('请至少扫描一个HandlingUnit'); return; }
// 构建HandlingUnit ID列表
const handlingUnitIds = this.scannedItems.map(item => item.unitId);
const params = { site: this.site, operatorName: this.outboundForm.operatorName, operateTime: this.outboundForm.operateTime, outboundReason: this.outboundForm.outboundReason, handlingUnitIds: handlingUnitIds, scannedItems: this.scannedItems };
// 调用后端API
confirmOtherOutbound(params).then(({ data }) => { if (data && data.code === 0) { this.$message({ message: '其它出库成功!处理单元: ' + handlingUnitIds.length + '个', type: 'success', duration: 3000 });
// 跳转回其他出入库页面
setTimeout(() => { this.$router.push({ path: '/otherinout' }); }, 1000); } else { this.$message.error(data.msg || '其它出库失败'); } }).catch(error => { console.error('其它出库失败:', error); this.$message.error('其它出库失败,请重试'); }); },
// 取消处理
cancelProcess() { if (this.scannedItems.length > 0) { this.$confirm('确认取消当前操作?已扫描的数据将会丢失。', '确认', { confirmButtonText: '确定', cancelButtonText: '取消', type: 'warning' }).then(() => { this.$router.go(-1); }).catch(() => { // 用户取消,不做任何操作
}); } else { this.$router.go(-1); } },
// 初始化表单数据
initFormData() { // 设置默认操作时间为当前时间
const now = new Date(); const year = now.getFullYear(); const month = (now.getMonth() + 1).toString().padStart(2, '0'); const day = now.getDate().toString().padStart(2, '0'); const hours = now.getHours().toString().padStart(2, '0'); const minutes = now.getMinutes().toString().padStart(2, '0'); const seconds = now.getSeconds().toString().padStart(2, '0');
this.outboundForm.operateTime = year + '-' + month + '-' + day + ' ' + hours + ':' + minutes + ':' + seconds;
// 设置默认操作员
this.outboundForm.operatorName = localStorage.getItem('userName') || '系统用户'; } }, mounted() { this.initFormData(); this.$nextTick(() => { if (this.$refs.scanInput) { this.$refs.scanInput.focus(); } }); }};</script>
<style scoped>/* 复用其它入库的样式 */.pda-container { width: 100%; height: 100vh; display: flex; flex-direction: column; overflow: hidden;}
.status-bar { background: #17B3A3; color: white; padding: 8px 16px; display: flex; justify-content: space-between; align-items: center; height: 40px; min-height: 40px;}
.goBack { cursor: pointer; font-size: 16px; font-weight: 500;}
/* 搜索容器样式 */.search-container { padding: 12px 16px; background: white; display: flex; align-items: center; gap: 12px;}
.search-container .el-input { width: 240px; margin-right: 12px;}
/* 紧凑型输入框样式 */.compact-input ::v-deep .el-input__inner { height: 36px; padding: 0 12px 0 35px; font-size: 14px;}
.compact-input ::v-deep .el-input__prefix { left: 10px;}
.compact-input ::v-deep .el-input__suffix { right: 30px;}
/* 模式切换开关 */.mode-switch { position: relative; display: inline-block;}
.custom-switch { transform: scale(1.3);}
/* 中间文字 */.switch-text { position: absolute; left: 25%; top: 53%; transform: translate(-50%, -50%); font-size: 12px; font-weight: bold; color: white; pointer-events: none; z-index: 2;}
.switch-text2 { position: absolute; left: 75%; top: 53%; transform: translate(-50%, -50%); font-size: 12px; font-weight: bold; color: white; pointer-events: none; z-index: 2;}
/* 调整 switch 尺寸以便容纳文字 */.custom-switch ::v-deep .el-switch__core { width: 60px; height: 28px;}
/* 物料信息卡片 */.material-info-card { background: white; margin: 4px 16px; padding: 6px 20px; border-radius: 8px; box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1); border: 1px solid #f0f0f0;}
.card-title { margin-bottom: 8px; display: flex; align-items: center; gap: 8px;}
.title-label { font-size: 12px; color: #666; font-weight: 500;}
.title-value { font-size: 16px; font-weight: bold; color: #333; line-height: 1.2;}
/* 表单样式 */.input-form { margin-top: 8px;}
.form-row { display: flex; gap: 12px; margin-bottom: 12px;}
.form-row:last-child { margin-bottom: 0;}
.form-item { flex: 1; display: flex; flex-direction: column;}
.form-item.full-width { flex: none; width: 100%;}
.form-label { font-size: 11px; color: #666; font-weight: 500; margin-bottom: 4px; display: block;}
.form-item .el-input { width: 100%;}
.form-item .el-date-editor { width: 100%;}
/* 区域标题 */.section-title { display: flex; align-items: center; justify-content: space-between; padding: 6px 8px; background: white; margin: 0 16px; margin-top: 4px; border-radius: 8px 8px 0 0; border-bottom: 2px solid #17B3A3;}
.title-left { display: flex; align-items: center;}
.title-left i { color: #17B3A3; font-size: 16px; margin-right: 8px;}
.title-left span { color: #17B3A3; font-size: 14px; font-weight: 500;}
/* 标签列表 */.label-list { background: white; margin: 0 16px 12px; border-radius: 0 0 8px 8px; overflow: hidden;}
.label-list .el-form-item { margin-bottom: 1px;}
.label-list .el-form-item__label { padding-bottom: 1px; margin-bottom: 0; line-height: 1.1; font-size: 11px;}
.label-list .el-form-item__content { line-height: 1.2; font-size: 12px;}
.bottom-line-row { border-bottom: 1px solid #f0f0f0; margin-bottom: 8px; padding-bottom: 8px;}
.empty-labels { padding: 20px; text-align: center; color: #999; background: white; margin: 0 16px; border-radius: 8px;}
/* 底部操作按钮 */.bottom-actions { display: flex; padding: 16px; gap: 20px; background: white; margin-top: auto;}
.action-btn { flex: 1; padding: 12px; border: 1px solid #17B3A3; background: #17B3A3; color: white; border-radius: 20px; font-size: 14px; cursor: pointer; transition: all 0.2s ease;}
.action-btn.secondary { background: white; color: #17B3A3;}
.action-btn:hover { background: #0d8f7f; border-color: #0d8f7f;}
.action-btn.secondary:hover { background: #17B3A3; color: white;}
.action-btn:active { transform: scale(0.98);}
/* 响应式设计 */@media (max-width: 360px) { .status-bar { padding: 8px 12px; }
.search-container { padding: 8px 12px; }
.material-info-card { margin: 4px 12px; padding: 6px 16px; }
.item-list { margin: 0 12px 8px; }
.form-row { gap: 8px; margin-bottom: 8px; }
.form-label { font-size: 10px; margin-bottom: 2px; }}</style>
|