4 changed files with 577 additions and 0 deletions
-
3src/api/automatedWarehouse/callOut.js
-
1src/router/index.js
-
6src/views/main.vue
-
567src/views/modules/automatedWarehouse/callOutForHetuo.vue
@ -0,0 +1,567 @@ |
|||||
|
<template> |
||||
|
<div> |
||||
|
<div class="pda-container"> |
||||
|
<!-- 头部栏 --> |
||||
|
<div class="header-bar"> |
||||
|
<div class="header-left" @click="handleBack"> |
||||
|
<i class="el-icon-arrow-left"></i> |
||||
|
<span>Call栈板手工合托</span> |
||||
|
</div> |
||||
|
<div class="header-right" @click="$router.push({ path: '/' })"> |
||||
|
首页 |
||||
|
</div> |
||||
|
</div> |
||||
|
<!-- 搜索框 --> |
||||
|
<!-- <div class="search-container">--> |
||||
|
<!-- --> |
||||
|
<!-- </div>--> |
||||
|
<div class="table-body" style="max-height: 500px; overflow-y: auto;"> |
||||
|
<div class="main-content form-section"> |
||||
|
<!-- 表单区域 --> |
||||
|
|
||||
|
<!-- @blur="handlePartNoBlur"--> |
||||
|
<!-- 栈板编码搜索框 - rqrq --> |
||||
|
<div class="input-group"> |
||||
|
<label class="input-label">栈板编码(扫描后自动下达)</label> |
||||
|
<el-input |
||||
|
v-model="formData.palletId" |
||||
|
placeholder="请扫描或输入栈板编码" |
||||
|
class="form-input" |
||||
|
clearable |
||||
|
ref="palletInput" |
||||
|
@keyup.enter.native="handleScanAndCall" |
||||
|
:disabled="scanLoading" |
||||
|
/> |
||||
|
</div> |
||||
|
|
||||
|
<!-- 下达状态提示 - rqrq --> |
||||
|
<div v-if="scanLoading" class="status-tip loading"> |
||||
|
<i class="el-icon-loading"></i> 正在下达中... |
||||
|
</div> |
||||
|
|
||||
|
<div class="bottom-actions" style="display: flex; gap: 10px; flex-wrap: nowrap;"> |
||||
|
<button |
||||
|
class="action-btn primary" |
||||
|
@click="handleScanAndCall" |
||||
|
:disabled="scanLoading || !formData.palletId" |
||||
|
style="flex: 2;" |
||||
|
> |
||||
|
{{ scanLoading ? '下达中...' : '扫描下达' }} |
||||
|
</button> |
||||
|
|
||||
|
<button class="action-btn secondary" @click="cleanData" :disabled="scanLoading" style="flex: 1;"> |
||||
|
清空 |
||||
|
</button> |
||||
|
</div> |
||||
|
|
||||
|
<!-- 下达记录列表 - rqrq --> |
||||
|
<div v-if="callHistory.length > 0" class="history-section"> |
||||
|
<div class="list-title">本次下达记录({{ callHistory.length }}条)</div> |
||||
|
<div v-for="(record, index) in callHistory" :key="index" class="history-item" :class="record.success ? 'success' : 'error'"> |
||||
|
<span class="history-pallet">{{ record.palletId }}</span> |
||||
|
<span class="history-status">{{ record.success ? '✓ 成功' : '✗ ' + record.reason }}</span> |
||||
|
<span class="history-time">{{ record.time }}</span> |
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
|
||||
|
<!-- 栈板列表(保留,用于手动模式)- rqrq --> |
||||
|
<div v-if="palletList.length > 0" class="rma-list"> |
||||
|
<!-- Call车按钮 - 当有选中栈板时显示 --> |
||||
|
|
||||
|
<div class="list-title" style="flex: 0.75">可用栈板列表</div> |
||||
|
|
||||
|
<el-form> |
||||
|
<el-row v-for="(pallet, index) in palletList" :key="index" class="rma-row"> |
||||
|
<el-col :span="24"> |
||||
|
<div class="rma-item" @click="selectPallet(pallet)" :class="{ 'selected': isSelected(pallet) }"> |
||||
|
<div class="item-info"> |
||||
|
<span class="part-no">栈板号: {{ pallet.palletId }}</span> |
||||
|
<!-- rqrq - 如果有物料编码,显示明细;否则只显示栈板 --> |
||||
|
<span class="batch-qty" v-if="pallet.partNo"> |
||||
|
物料: {{ pallet.partNo }} | 数量: {{ pallet.qty }} |
||||
|
</span> |
||||
|
<span class="batch-qty" v-if="pallet.partNo && pallet.batchNo"> |
||||
|
| 批号: {{ pallet.batchNo }} |
||||
|
</span> |
||||
|
<span class="batch-qty" v-if="pallet.partNo && pallet.wdr"> |
||||
|
| WDR: {{ pallet.wdr }} |
||||
|
</span> |
||||
|
<span class="batch-qty" v-if="pallet.partNo && pallet.expiredDate"> |
||||
|
| 失效日期: {{ pallet.expiredDate }} |
||||
|
</span> |
||||
|
</div> |
||||
|
<div class="item-status"> |
||||
|
<i class="el-icon-check" v-if="isSelected(pallet)"></i> |
||||
|
</div> |
||||
|
</div> |
||||
|
</el-col> |
||||
|
</el-row> |
||||
|
</el-form> |
||||
|
|
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
</template> |
||||
|
|
||||
|
<script> |
||||
|
|
||||
|
import { |
||||
|
saveTransportTask, |
||||
|
getShopOrderFromIFSWithOrderNo, |
||||
|
getPalletList, |
||||
|
callPalletFromWcs, |
||||
|
callPalletFromWcsNew, |
||||
|
scanAndCallPalletForHetuo |
||||
|
} from '../../../api/automatedWarehouse/callOut' |
||||
|
|
||||
|
export default { |
||||
|
data() { |
||||
|
return { |
||||
|
scanRma: "", |
||||
|
rmaList: [], |
||||
|
returnList: [], // 退货明细列表 |
||||
|
selectedDetail: null, // 当前选择的RMA明细 |
||||
|
processType: "inbound", // 固定为入库处理 |
||||
|
site:localStorage.getItem('site'), |
||||
|
loading: false, // 查询物料明细的loading状态 |
||||
|
lastPartNo: '', // 记录最后查询的物料编码,避免重复查询 |
||||
|
formData: { |
||||
|
palletId: '', // 栈板编码 - rqrq |
||||
|
partNo: '', |
||||
|
partDesc: '', |
||||
|
batchNo: '', |
||||
|
rollNo: '', |
||||
|
site:localStorage.getItem('site'), |
||||
|
}, |
||||
|
palletList: [], // 栈板列表 |
||||
|
selectedPallet: null, // 选中的栈板 |
||||
|
selectedPallets: [], // 多选时选中的栈板列表 |
||||
|
callLoading: false, // Call车按钮loading状态 - rqrq |
||||
|
scanLoading: false, // 扫描下达loading状态 - rqrq |
||||
|
callHistory: [], // 下达记录列表 - rqrq |
||||
|
}; |
||||
|
}, |
||||
|
computed: { |
||||
|
|
||||
|
}, |
||||
|
methods: { |
||||
|
handleBack() { |
||||
|
this.$router.back(); |
||||
|
}, |
||||
|
|
||||
|
// 处理物料编码失去焦点事件 |
||||
|
async handlePartNoBlur() { |
||||
|
const partNo = this.formData.partNo; |
||||
|
if (!partNo) { |
||||
|
this.formData.partDesc = ''; |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
// 如果物料编码没有变化,不重复查询 |
||||
|
// if (this.lastPartNo === partNo) { |
||||
|
// return; |
||||
|
// } |
||||
|
|
||||
|
this.loading = true; |
||||
|
getShopOrderFromIFSWithOrderNo({ |
||||
|
site: this.formData.site, |
||||
|
partNo: partNo |
||||
|
}).then(({ data }) => { |
||||
|
this.loading = false; |
||||
|
if (data.code === 0) { |
||||
|
let rows=data.rows |
||||
|
if(rows.length>0){ |
||||
|
this.formData.partDesc = rows[0].description || ''; |
||||
|
}else { |
||||
|
this.formData.partDesc = ''; |
||||
|
this.$alert('没有找到该物料编码', '错误', { |
||||
|
confirmButtonText: '确定', |
||||
|
}) |
||||
|
} |
||||
|
|
||||
|
} else { |
||||
|
// 查询失败或没有数据 |
||||
|
this.formData.partDesc = ''; |
||||
|
this.$alert(data.msg, '错误', { |
||||
|
confirmButtonText: '确定', |
||||
|
}) |
||||
|
} |
||||
|
}) |
||||
|
|
||||
|
}, |
||||
|
|
||||
|
// 查询栈板列表 - rqrq 修改校验逻辑:物料编码和栈板码至少填一个 |
||||
|
confirmDo() { |
||||
|
// 校验:物料编码和栈板码至少填一个 - rqrq |
||||
|
if((!this.formData.partNo || this.formData.partNo === '') && |
||||
|
(!this.formData.palletId || this.formData.palletId === '')){ |
||||
|
this.$alert('请输入物料编码或栈板编码', '提示', { |
||||
|
confirmButtonText: '确定' |
||||
|
}); |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
// 构建查询参数 - rqrq |
||||
|
const queryParams = { |
||||
|
site: this.formData.site |
||||
|
}; |
||||
|
|
||||
|
// 添加栈板码到查询参数 - rqrq |
||||
|
if (this.formData.palletId && this.formData.palletId.trim()) { |
||||
|
queryParams.palletId = this.formData.palletId.trim(); |
||||
|
} |
||||
|
|
||||
|
// 添加物料编码到查询参数 - rqrq |
||||
|
if (this.formData.partNo && this.formData.partNo.trim()) { |
||||
|
queryParams.partNo = this.formData.partNo.trim(); |
||||
|
} |
||||
|
|
||||
|
// 如果有批号,添加到查询参数 |
||||
|
if (this.formData.batchNo && this.formData.batchNo.trim()) { |
||||
|
queryParams.batchNo = this.formData.batchNo.trim(); |
||||
|
} |
||||
|
|
||||
|
getPalletList(queryParams).then(({ data }) => { |
||||
|
if (data && data.code === 0) { |
||||
|
this.palletList = data.rows || []; |
||||
|
//如果有些是用batchNo查的 这些字段要一起加进去 呼叫栈板时保存 |
||||
|
if (this.palletList.length === 0) { |
||||
|
this.$message.warning('未找到满足条件的栈板'); |
||||
|
} else { |
||||
|
this.$message.success(`找到 ${this.palletList.length} 个栈板`); |
||||
|
} |
||||
|
// 清空之前选中的栈板 |
||||
|
this.selectedPallet = null; |
||||
|
this.selectedPallets = []; // 清空多选选中的栈板 |
||||
|
} else { |
||||
|
this.$alert(data.msg || '查询失败', '错误', { |
||||
|
confirmButtonText: '确定' |
||||
|
}); |
||||
|
this.palletList = []; |
||||
|
this.selectedPallet = null; |
||||
|
this.selectedPallets = []; // 清空多选选中的栈板 |
||||
|
} |
||||
|
}).catch(error => { |
||||
|
console.error('查询栈板列表失败:', error); |
||||
|
this.$alert(error.message || '查询失败', '错误', { |
||||
|
confirmButtonText: '确定' |
||||
|
}); |
||||
|
this.palletList = []; |
||||
|
this.selectedPallet = null; |
||||
|
this.selectedPallets = []; // 清空多选选中的栈板 |
||||
|
}); |
||||
|
}, |
||||
|
|
||||
|
// 选择栈板 - rqrq 修改逻辑:按栈板ID选择,支持同一栈板多条明细 |
||||
|
selectPallet(pallet) { |
||||
|
const palletId = pallet.palletId; |
||||
|
const index = this.selectedPallets.findIndex(item => item.palletId === palletId); |
||||
|
|
||||
|
if (index > -1) { |
||||
|
// 如果已选中,取消选择(移除该栈板)- rqrq |
||||
|
this.selectedPallets.splice(index, 1); |
||||
|
this.$message.success('已取消选择栈板'); |
||||
|
} else { |
||||
|
// 如果未选中,选择该栈板(只添加一条记录用于Call)- rqrq |
||||
|
this.selectedPallets.push({ |
||||
|
site: pallet.site, |
||||
|
palletId: pallet.palletId, |
||||
|
partNo: pallet.partNo || '', // 如果没有物料,传空字符串 |
||||
|
qty: pallet.qty || 0, |
||||
|
batchNo: pallet.batchNo || this.formData.batchNo || '' |
||||
|
}); |
||||
|
this.$message.success(`已选择栈板: ${palletId}`); |
||||
|
} |
||||
|
}, |
||||
|
|
||||
|
// 判断栈板是否被选中 - rqrq |
||||
|
isSelected(pallet) { |
||||
|
return this.selectedPallets.some(item => item.palletId === pallet.palletId); |
||||
|
}, |
||||
|
|
||||
|
// 处理Call按钮点击 - rqrq |
||||
|
handleCall() { |
||||
|
if (this.selectedPallets.length === 0) { |
||||
|
this.$alert('请至少选择一个栈板', '提示', { |
||||
|
confirmButtonText: '确定' |
||||
|
}); |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
this.$confirm(`确定Call ${this.selectedPallets.length} 个栈板出库?`, '提示', { |
||||
|
confirmButtonText: '确认', |
||||
|
cancelButtonText: '取消', |
||||
|
type: 'warning' |
||||
|
}).then(() => { |
||||
|
// 设置loading状态 - rqrq |
||||
|
this.callLoading = true; |
||||
|
|
||||
|
// 调用新的接口 - rqrq |
||||
|
callPalletFromWcsNew(this.selectedPallets).then(({ data }) => { |
||||
|
if (data && data.code === 0) { |
||||
|
const failedCount = data.failedCount || 0; |
||||
|
const successCount = data.successCount || 0; |
||||
|
|
||||
|
// 判断是否有失败 - rqrq |
||||
|
if (failedCount === 0) { |
||||
|
// 全部成功 - rqrq |
||||
|
this.$message.success(`成功Call ${successCount} 个栈板出库!`); |
||||
|
this.cleanData(); |
||||
|
} else { |
||||
|
// 有失败的栈板 - rqrq |
||||
|
const failedPalletIds = data.failedPalletIds || []; |
||||
|
const failedReasons = data.failedReasons || []; |
||||
|
|
||||
|
// 构建失败信息 - rqrq |
||||
|
let errorMsg = `成功:${successCount}个,失败:${failedCount}个\n\n失败栈板:\n`; |
||||
|
failedPalletIds.forEach((palletId, index) => { |
||||
|
errorMsg += `${index + 1}. ${palletId}:${failedReasons[index] || '未知错误'}\n`; |
||||
|
}); |
||||
|
|
||||
|
// 显示失败信息弹窗 - rqrq |
||||
|
this.$alert(errorMsg, `Call车结果`, { |
||||
|
confirmButtonText: '确定', |
||||
|
type: 'warning', |
||||
|
callback: () => { |
||||
|
// 点击确定后初始化页面 - rqrq |
||||
|
this.cleanData(); |
||||
|
} |
||||
|
}); |
||||
|
} |
||||
|
} else { |
||||
|
this.$alert(data.msg || 'Call车失败', '错误', { |
||||
|
confirmButtonText: '确定' |
||||
|
}); |
||||
|
} |
||||
|
}).catch(error => { |
||||
|
console.error('Call车失败:', error); |
||||
|
this.$alert(error.message || 'Call车失败', '错误', { |
||||
|
confirmButtonText: '确定' |
||||
|
}); |
||||
|
}).finally(() => { |
||||
|
// 恢复按钮状态 - rqrq |
||||
|
this.callLoading = false; |
||||
|
}); |
||||
|
}).catch(() => { |
||||
|
// 用户取消操作 - rqrq |
||||
|
}); |
||||
|
}, |
||||
|
|
||||
|
cleanData(){ |
||||
|
// 更安全的清空方式 - rqrq |
||||
|
this.formData = { |
||||
|
palletId: '', // 栈板编码 - rqrq |
||||
|
partNo: '', |
||||
|
partDesc: '', |
||||
|
batchNo: '', |
||||
|
rollNo: '', |
||||
|
site:localStorage.getItem('site'), |
||||
|
}; |
||||
|
// 清空栈板列表和选中状态 |
||||
|
this.palletList = []; |
||||
|
this.selectedPallet = null; |
||||
|
this.selectedPallets = []; // 清空多选选中的栈板 |
||||
|
// 清空下达记录 - rqrq |
||||
|
this.callHistory = []; |
||||
|
// 聚焦到输入框 - rqrq |
||||
|
this.focusInput(); |
||||
|
}, |
||||
|
|
||||
|
// 聚焦到输入框 - rqrq |
||||
|
focusInput() { |
||||
|
this.$nextTick(() => { |
||||
|
if (this.$refs.palletInput) { |
||||
|
this.$refs.palletInput.focus(); |
||||
|
} |
||||
|
}); |
||||
|
}, |
||||
|
|
||||
|
// 获取当前时间字符串 - rqrq |
||||
|
getCurrentTime() { |
||||
|
const now = new Date(); |
||||
|
return now.getHours().toString().padStart(2, '0') + ':' + |
||||
|
now.getMinutes().toString().padStart(2, '0') + ':' + |
||||
|
now.getSeconds().toString().padStart(2, '0'); |
||||
|
}, |
||||
|
|
||||
|
// 扫描并直接下达 - rqrq |
||||
|
handleScanAndCall() { |
||||
|
const palletId = this.formData.palletId ? this.formData.palletId.trim() : ''; |
||||
|
|
||||
|
if (!palletId) { |
||||
|
this.$message.warning('请输入或扫描栈板编码'); |
||||
|
this.focusInput(); |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
// 设置loading状态 - rqrq |
||||
|
this.scanLoading = true; |
||||
|
|
||||
|
// 调用后端扫描下达接口 - rqrq |
||||
|
scanAndCallPalletForHetuo({ |
||||
|
site: this.formData.site, |
||||
|
palletId: palletId |
||||
|
}).then(({ data }) => { |
||||
|
if (data && data.code === 0) { |
||||
|
const failedCount = data.failedCount || 0; |
||||
|
const successCount = data.successCount || 0; |
||||
|
|
||||
|
if (failedCount === 0 && successCount > 0) { |
||||
|
// 下达成功 - rqrq |
||||
|
this.$message.success('栈板【' + palletId + '】下达成功!'); |
||||
|
// 添加到下达记录 - rqrq |
||||
|
this.callHistory.unshift({ |
||||
|
palletId: palletId, |
||||
|
success: true, |
||||
|
reason: '', |
||||
|
time: this.getCurrentTime() |
||||
|
}); |
||||
|
} else if (failedCount > 0) { |
||||
|
// 下达失败 - rqrq |
||||
|
const failedReasons = data.failedReasons || []; |
||||
|
const errorMsg = failedReasons.length > 0 ? failedReasons[0] : '未知错误'; |
||||
|
this.$message.error('下达失败:' + errorMsg); |
||||
|
// 添加到下达记录 - rqrq |
||||
|
this.callHistory.unshift({ |
||||
|
palletId: palletId, |
||||
|
success: false, |
||||
|
reason: errorMsg, |
||||
|
time: this.getCurrentTime() |
||||
|
}); |
||||
|
} |
||||
|
} else { |
||||
|
// 接口返回错误 - rqrq |
||||
|
const errorMsg = data.msg || '下达失败'; |
||||
|
this.$message.error(errorMsg); |
||||
|
// 添加到下达记录 - rqrq |
||||
|
this.callHistory.unshift({ |
||||
|
palletId: palletId, |
||||
|
success: false, |
||||
|
reason: errorMsg, |
||||
|
time: this.getCurrentTime() |
||||
|
}); |
||||
|
} |
||||
|
}).catch(error => { |
||||
|
console.error('扫描下达失败:', error); |
||||
|
const errorMsg = error.message || '下达失败'; |
||||
|
this.$message.error(errorMsg); |
||||
|
// 添加到下达记录 - rqrq |
||||
|
this.callHistory.unshift({ |
||||
|
palletId: palletId, |
||||
|
success: false, |
||||
|
reason: errorMsg, |
||||
|
time: this.getCurrentTime() |
||||
|
}); |
||||
|
}).finally(() => { |
||||
|
// 恢复状态 - rqrq |
||||
|
this.scanLoading = false; |
||||
|
// 清空输入框并聚焦,准备下一次扫描 - rqrq |
||||
|
this.formData.palletId = ''; |
||||
|
this.focusInput(); |
||||
|
// 只保留最近20条记录 - rqrq |
||||
|
if (this.callHistory.length > 20) { |
||||
|
this.callHistory = this.callHistory.slice(0, 20); |
||||
|
} |
||||
|
}); |
||||
|
}, |
||||
|
|
||||
|
}, |
||||
|
mounted() { |
||||
|
// 页面加载后自动聚焦到输入框 - rqrq |
||||
|
this.focusInput(); |
||||
|
} |
||||
|
}; |
||||
|
</script> |
||||
|
|
||||
|
<style scoped> |
||||
|
/* 按钮禁用状态样式 - rqrq */ |
||||
|
.action-btn:disabled { |
||||
|
opacity: 0.6; |
||||
|
cursor: not-allowed; |
||||
|
background-color: #ccc !important; |
||||
|
border-color: #ccc !important; |
||||
|
} |
||||
|
|
||||
|
/* 主要按钮样式 - rqrq */ |
||||
|
.action-btn.primary { |
||||
|
background-color: #409EFF; |
||||
|
border-color: #409EFF; |
||||
|
color: #fff; |
||||
|
} |
||||
|
|
||||
|
.action-btn.primary:hover:not(:disabled) { |
||||
|
background-color: #66b1ff; |
||||
|
border-color: #66b1ff; |
||||
|
} |
||||
|
|
||||
|
/* 状态提示样式 - rqrq */ |
||||
|
.status-tip { |
||||
|
padding: 10px; |
||||
|
margin: 10px 0; |
||||
|
border-radius: 4px; |
||||
|
text-align: center; |
||||
|
font-size: 14px; |
||||
|
} |
||||
|
|
||||
|
.status-tip.loading { |
||||
|
background-color: #e6f7ff; |
||||
|
color: #1890ff; |
||||
|
border: 1px solid #91d5ff; |
||||
|
} |
||||
|
|
||||
|
/* 下达记录区域样式 - rqrq */ |
||||
|
.history-section { |
||||
|
margin-top: 15px; |
||||
|
border-top: 1px solid #eee; |
||||
|
padding-top: 10px; |
||||
|
} |
||||
|
|
||||
|
.history-item { |
||||
|
display: flex; |
||||
|
justify-content: space-between; |
||||
|
align-items: center; |
||||
|
padding: 8px 10px; |
||||
|
margin: 5px 0; |
||||
|
border-radius: 4px; |
||||
|
font-size: 13px; |
||||
|
} |
||||
|
|
||||
|
.history-item.success { |
||||
|
background-color: #f0f9eb; |
||||
|
border-left: 3px solid #67c23a; |
||||
|
} |
||||
|
|
||||
|
.history-item.error { |
||||
|
background-color: #fef0f0; |
||||
|
border-left: 3px solid #f56c6c; |
||||
|
} |
||||
|
|
||||
|
.history-pallet { |
||||
|
font-weight: bold; |
||||
|
color: #333; |
||||
|
flex: 1; |
||||
|
} |
||||
|
|
||||
|
.history-status { |
||||
|
flex: 2; |
||||
|
text-align: center; |
||||
|
} |
||||
|
|
||||
|
.history-item.success .history-status { |
||||
|
color: #67c23a; |
||||
|
} |
||||
|
|
||||
|
.history-item.error .history-status { |
||||
|
color: #f56c6c; |
||||
|
font-size: 12px; |
||||
|
} |
||||
|
|
||||
|
.history-time { |
||||
|
color: #999; |
||||
|
font-size: 12px; |
||||
|
flex: 0.5; |
||||
|
text-align: right; |
||||
|
} |
||||
|
</style> |
||||
Write
Preview
Loading…
Cancel
Save
Reference in new issue