8 changed files with 1642 additions and 0 deletions
-
12src/api/haianAutoWarehouse/cancelWcsPallet.js
-
15src/api/haianAutoWarehouse/emptyPalletAssembly.js
-
15src/api/haianAutoWarehouse/palletMerge.js
-
3src/router/index.js
-
18src/views/main.vue
-
516src/views/modules/haianAutoWarehouse/haianCancelWcsPallet.vue
-
467src/views/modules/haianAutoWarehouse/haianEmptyPalletAssembly.vue
-
596src/views/modules/haianAutoWarehouse/haianPalletMerge.vue
@ -0,0 +1,12 @@ |
|||
import { createAPI } from "@/utils/httpRequest.js"; |
|||
|
|||
// ========== 海安-取消WCS组盘相关接口 ========== - rqrq
|
|||
|
|||
// 海安-检查栈板组盘状态(返回callingFlag/canOperate/isEmpty)- rqrq
|
|||
export const checkPalletWcsStatus = data => createAPI(`/haiAnWcsIntegration/checkPalletWcsStatus`, 'post', data) |
|||
|
|||
// 海安-取消组盘 - rqrq
|
|||
export const cancelWcsPallet = data => createAPI(`/haiAnWcsIntegration/cancelWcsPallet`, 'post', data) |
|||
|
|||
// 海安-移出全部物料 - rqrq
|
|||
export const removeAllPalletDetails = data => createAPI(`/haiAnWcsIntegration/removeAllPalletDetails`, 'post', data) |
|||
@ -0,0 +1,15 @@ |
|||
import { createAPI } from "@/utils/httpRequest.js"; |
|||
|
|||
// ========== 海安-空托盘组盘相关接口 ========== - rqrq
|
|||
|
|||
// 海安-检查是否为空托盘(haian_pallet_detail无数据)- rqrq
|
|||
export const checkEmptyPallet = data => createAPI(`/haiAnWcsIntegration/checkEmptyPallet`, 'post', data) |
|||
|
|||
// 海安-获取托盘类型列表(兼容旧页面接口名)- rqrq
|
|||
export const getPalletTypes = data => createAPI(`/haiAnWcsIntegration/getPalletTypes`, 'post', data) |
|||
|
|||
// 海安-更新托盘类型与自动分拣标识 - rqrq
|
|||
export const updatePalletTypeAndAutoSort = data => createAPI(`/haiAnWcsIntegration/updatePalletTypeAndAutoSort`, 'post', data) |
|||
|
|||
// 海安-空托盘通知入库(transportFlag=N仅入库,Y入库并运输)- rqrq
|
|||
export const notifyEmptyPalletInbound = data => createAPI(`/haiAnWcsIntegration/notifyEmptyPalletInbound`, 'post', data) |
|||
@ -0,0 +1,15 @@ |
|||
import { createAPI } from "@/utils/httpRequest.js"; |
|||
|
|||
// ========== 海安-合托相关接口 ========== - rqrq
|
|||
|
|||
// 海安-校验托盘(来源/目标通用)- rqrq
|
|||
export const checkPalletForMerge = data => createAPI(`/haiAnWcsIntegration/checkPalletForMerge`, 'post', data) |
|||
|
|||
// 海安-校验目标托盘类型是否为混装托盘 - rqrq
|
|||
export const checkTargetPalletType = data => createAPI(`/haiAnWcsIntegration/checkTargetPalletType`, 'post', data) |
|||
|
|||
// 海安-查询托盘明细(用于合托查看)- rqrq
|
|||
export const getPalletDetailForMerge = data => createAPI(`/haiAnWcsIntegration/getPalletDetailForMerge`, 'post', data) |
|||
|
|||
// 海安-执行合托(来源托盘明细并入目标托盘)- rqrq
|
|||
export const executePalletMerge = data => createAPI(`/haiAnWcsIntegration/executePalletMerge`, 'post', data) |
|||
@ -0,0 +1,516 @@ |
|||
<template> |
|||
<div> |
|||
<div class="pda-container"> |
|||
<!-- 头部栏 - rqrq --> |
|||
<div class="header-bar"> |
|||
<div class="header-left" @click="handleBack"> |
|||
<i class="el-icon-arrow-left"></i> |
|||
<span>取消WCS组盘任务</span> |
|||
</div> |
|||
<div class="header-right" @click="goHome"> |
|||
首页 |
|||
</div> |
|||
</div> |
|||
|
|||
<div class="table-body" style="max-height: 600px; 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" |
|||
inputmode="none" |
|||
autocomplete="off" |
|||
autocorrect="off" |
|||
spellcheck="false" |
|||
ref="palletInput" |
|||
/> |
|||
</div> |
|||
|
|||
<!-- 栈板信息显示(扫描栈板后显示)- rqrq --> |
|||
<div v-if="palletScanned" class="pallet-info-section"> |
|||
|
|||
<div class="info-row"> |
|||
<label class="info-label">是否被调用:</label> |
|||
<span class="info-value" :style="{color: palletInfo.callingFlag === 'Y' ? '#F56C6C' : '#67C23A'}"> |
|||
{{ palletInfo.callingFlag === 'Y' ? '是' : '否' }} |
|||
</span> |
|||
</div> |
|||
|
|||
<!-- 是否发送组盘任务 - rqrq --> |
|||
<div class="info-row"> |
|||
<label class="info-label">是否已组盘:</label> |
|||
<span class="info-value" :style="{color: hasSentWcsTask ? '#F56C6C' : '#67C23A'}"> |
|||
{{ hasSentWcsTask ? '是' : '否' }} |
|||
</span> |
|||
</div> |
|||
|
|||
<!-- 浏览明细按钮 - rqrq --> |
|||
<div class="button-row"> |
|||
<button class="action-btn primary" @click="showDetailModal" style="width: 100%;"> |
|||
浏览明细 ({{ detailList.length }}条) |
|||
</button> |
|||
</div> |
|||
|
|||
<!-- 取消组盘按钮(只有发送了组盘任务才显示)- rqrq --> |
|||
<div class="button-row"> |
|||
<button |
|||
class="action-btn primary" |
|||
@click="handleCancelWcsPallet" |
|||
style="width: 100%;"> |
|||
{{ cancelLoading ? '取消中...' : '取消组盘' }} |
|||
</button> |
|||
</div> |
|||
|
|||
<!-- 移出全部物料按钮(只有未发送组盘任务且未被调用且有明细才显示)- rqrq --> |
|||
<div v-if="showRemoveAllButton" class="button-row"> |
|||
<button |
|||
class="action-btn warning" |
|||
@click="handleRemoveAllMaterials" |
|||
:disabled="removeAllLoading" |
|||
style="width: 100%;"> |
|||
{{ removeAllLoading ? '移出中...' : '移出全部物料' }} |
|||
</button> |
|||
</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> |
|||
</div> |
|||
</template> |
|||
|
|||
<script> |
|||
import { |
|||
getPalletDetails |
|||
} from '../../../api/haianAutoWarehouse/palletPacking' |
|||
import { |
|||
checkPalletWcsStatus, |
|||
cancelWcsPallet, |
|||
removeAllPalletDetails |
|||
} from '../../../api/haianAutoWarehouse/cancelWcsPallet' |
|||
|
|||
export default { |
|||
data() { |
|||
return { |
|||
// 海安PDA前端site唯一来源为store用户对象,兼容旧缓存兜底 - rqrq |
|||
site: (this.$store && this.$store.state && this.$store.state.user && this.$store.state.user.site) || localStorage.getItem('site'), |
|||
|
|||
// 栈板信息 - rqrq |
|||
palletCode: '', |
|||
palletScanned: false, |
|||
palletInfo: { |
|||
callingFlag: '', |
|||
canOperate: '', |
|||
isEmpty: '' |
|||
}, |
|||
|
|||
// 按钮显示控制 - rqrq |
|||
hasSentWcsTask: false, |
|||
showCancelButton: false, |
|||
showRemoveAllButton: false, |
|||
|
|||
// 栈板明细 - rqrq |
|||
detailList: [], |
|||
detailModalVisible: false, |
|||
|
|||
// 加载状态 - rqrq |
|||
cancelLoading: false, |
|||
removeAllLoading: false |
|||
}; |
|||
}, |
|||
methods: { |
|||
// 返回上一页并清空页面状态,避免keep-alive导致脏数据残留 - rqrq |
|||
handleBack() { |
|||
this.resetPage(false); |
|||
this.$router.back(); |
|||
}, |
|||
|
|||
// 回首页前清理状态,保证再次进入页面从干净态开始 - rqrq |
|||
goHome() { |
|||
this.resetPage(false); |
|||
this.$router.push({ path: '/' }); |
|||
}, |
|||
|
|||
// 扫描栈板 - rqrq |
|||
handlePalletScan() { |
|||
if (!this.palletCode.trim()) { |
|||
this.$alert('请输入栈板编码', '提示', { |
|||
confirmButtonText: '确定' |
|||
}); |
|||
return; |
|||
} |
|||
|
|||
checkPalletWcsStatus({ |
|||
site: this.site, |
|||
palletId: this.palletCode |
|||
}).then(({ data }) => { |
|||
if (data.code === 0) { |
|||
// 后端返回正确的6位栈板码,赋值给输入框 - rqrq |
|||
this.palletCode = data.row.palletId; |
|||
|
|||
// 保存栈板信息 - rqrq |
|||
this.palletInfo = data.row; |
|||
this.palletScanned = true; |
|||
|
|||
// 解析按钮显示逻辑 - rqrq |
|||
// canOperate字段存储showCancelButton(是否显示取消组盘按钮)- rqrq |
|||
this.showCancelButton = data.row.canOperate === 'Y'; |
|||
|
|||
// isEmpty字段存储showRemoveAllButton(是否显示移出全部物料按钮)- rqrq |
|||
this.showRemoveAllButton = data.row.isEmpty === 'Y'; |
|||
|
|||
// 计算hasSentWcsTask(是否发送组盘任务)用于显示 - rqrq |
|||
this.hasSentWcsTask = this.showCancelButton; |
|||
|
|||
// 加载栈板明细 - rqrq |
|||
this.loadPalletDetails(); |
|||
|
|||
} else { |
|||
this.$alert(data.msg || '栈板不存在', '错误', { |
|||
confirmButtonText: '确定', |
|||
callback: () => { |
|||
this.palletCode = ''; |
|||
this.$nextTick(() => { |
|||
if (this.$refs.palletInput) { |
|||
this.$refs.palletInput.focus(); |
|||
} |
|||
}); |
|||
} |
|||
}); |
|||
} |
|||
}).catch(error => { |
|||
console.error('查询栈板失败:', error); |
|||
this.$alert(error.message || '查询栈板失败', '错误', { |
|||
confirmButtonText: '确定', |
|||
callback: () => { |
|||
this.palletCode = ''; |
|||
this.$nextTick(() => { |
|||
if (this.$refs.palletInput) { |
|||
this.$refs.palletInput.focus(); |
|||
} |
|||
}); |
|||
} |
|||
}); |
|||
}); |
|||
}, |
|||
|
|||
// 加载栈板明细 - rqrq |
|||
loadPalletDetails() { |
|||
getPalletDetails({ |
|||
site: this.site, |
|||
palletId: this.palletCode, |
|||
position: '', |
|||
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 |
|||
handleCancelWcsPallet() { |
|||
this.$confirm('确定要取消组盘吗?取消后需要重新组盘才能推送到WCS。', '确认操作', { |
|||
confirmButtonText: '确定', |
|||
cancelButtonText: '取消', |
|||
type: 'warning' |
|||
}).then(() => { |
|||
this.cancelLoading = true; |
|||
|
|||
cancelWcsPallet({ |
|||
site: this.site, |
|||
palletId: this.palletCode |
|||
}).then(({ data }) => { |
|||
if (data && data.code === 0) { |
|||
this.$message.success('取消组盘成功'); |
|||
// 重新扫描刷新信息 - rqrq |
|||
this.handlePalletScan(); |
|||
} else { |
|||
this.$alert(data.msg || '取消组盘失败', '错误', { |
|||
confirmButtonText: '确定' |
|||
}); |
|||
} |
|||
}).catch(error => { |
|||
console.error('取消组盘失败:', error); |
|||
// 网络错误也弹出提示框 - rqrq |
|||
this.$alert(error.message || '取消组盘失败', '错误', { |
|||
confirmButtonText: '确定' |
|||
}); |
|||
}).finally(() => { |
|||
this.cancelLoading = false; |
|||
}); |
|||
}).catch(() => { |
|||
// 用户取消操作 |
|||
}); |
|||
}, |
|||
|
|||
// 移出全部物料 - rqrq |
|||
handleRemoveAllMaterials() { |
|||
this.$confirm('确定要移出栈板上的全部物料吗?此操作不可恢复!', '确认操作', { |
|||
confirmButtonText: '确定', |
|||
cancelButtonText: '取消', |
|||
type: 'warning' |
|||
}).then(() => { |
|||
this.removeAllLoading = true; |
|||
|
|||
removeAllPalletDetails({ |
|||
site: this.site, |
|||
palletId: this.palletCode |
|||
}).then(({ data }) => { |
|||
if (data && data.code === 0) { |
|||
this.$message.success('移出全部物料成功'); |
|||
// 重新扫描刷新信息 - rqrq |
|||
this.handlePalletScan(); |
|||
} else { |
|||
this.$alert(data.msg || '移出全部物料失败', '错误', { |
|||
confirmButtonText: '确定' |
|||
}); |
|||
} |
|||
}).catch(error => { |
|||
console.error('移出全部物料失败:', error); |
|||
// 网络错误也弹出提示框 - rqrq |
|||
this.$alert(error.message || '移出全部物料失败', '错误', { |
|||
confirmButtonText: '确定' |
|||
}); |
|||
}).finally(() => { |
|||
this.removeAllLoading = false; |
|||
}); |
|||
}).catch(() => { |
|||
// 用户取消操作 |
|||
}); |
|||
}, |
|||
|
|||
// 重置页面并按需恢复扫码焦点,统一海安PDA页面生命周期清理行为 - rqrq |
|||
resetPage(needFocus) { |
|||
this.palletCode = ''; |
|||
this.palletScanned = false; |
|||
this.palletInfo = { |
|||
callingFlag: '', |
|||
canOperate: '', |
|||
isEmpty: '' |
|||
}; |
|||
this.hasSentWcsTask = false; |
|||
this.showCancelButton = false; |
|||
this.showRemoveAllButton = false; |
|||
this.detailList = []; |
|||
this.detailModalVisible = false; |
|||
|
|||
if (needFocus) { |
|||
this.$nextTick(() => { |
|||
if (this.$refs.palletInput) { |
|||
this.$refs.palletInput.focus(); |
|||
} |
|||
}); |
|||
} |
|||
} |
|||
}, |
|||
mounted() { |
|||
this.$nextTick(() => { |
|||
if (this.$refs.palletInput) { |
|||
this.$refs.palletInput.focus(); |
|||
} |
|||
}); |
|||
}, |
|||
activated() { |
|||
this.resetPage(true); |
|||
}, |
|||
beforeRouteLeave(to, from, next) { |
|||
this.resetPage(false); |
|||
next(); |
|||
} |
|||
}; |
|||
</script> |
|||
|
|||
<style scoped> |
|||
/* 栈板信息区域 - rqrq */ |
|||
.pallet-info-section { |
|||
margin-top: 16px; |
|||
padding: 12px; |
|||
background: #f5f7fa; |
|||
border-radius: 6px; |
|||
} |
|||
|
|||
.info-row { |
|||
display: flex; |
|||
align-items: center; |
|||
padding: 8px 0; |
|||
border-bottom: 1px solid #e4e7ed; |
|||
} |
|||
|
|||
.info-row:last-child { |
|||
border-bottom: none; |
|||
} |
|||
|
|||
.info-label { |
|||
font-weight: bold; |
|||
color: #606266; |
|||
width: 140px; |
|||
flex-shrink: 0; |
|||
} |
|||
|
|||
.info-value { |
|||
color: #303133; |
|||
font-size: 14px; |
|||
font-weight: bold; |
|||
} |
|||
|
|||
.button-row { |
|||
margin-top: 12px; |
|||
} |
|||
|
|||
/* 警告按钮 - rqrq */ |
|||
.action-btn.warning { |
|||
background-color: #E6A23C; |
|||
color: white; |
|||
border: none; |
|||
padding: 10px 20px; |
|||
border-radius: 4px; |
|||
cursor: pointer; |
|||
font-size: 14px; |
|||
} |
|||
|
|||
.action-btn.warning:hover { |
|||
background-color: #d99525; |
|||
} |
|||
|
|||
.action-btn.warning:disabled { |
|||
background-color: #f5dab1; |
|||
cursor: not-allowed; |
|||
} |
|||
|
|||
/* 表格样式 - rqrq */ |
|||
.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; |
|||
} |
|||
|
|||
/* 空数据提示 - rqrq */ |
|||
.empty-hint { |
|||
text-align: center; |
|||
color: #999; |
|||
padding: 20px; |
|||
background: white; |
|||
border-radius: 6px; |
|||
} |
|||
|
|||
/* 空数据行样式 - rqrq */ |
|||
.empty-row { |
|||
justify-content: center; |
|||
align-items: center; |
|||
padding: 20px; |
|||
border-bottom: none; |
|||
} |
|||
|
|||
.empty-row .empty-hint { |
|||
text-align: center; |
|||
color: #999; |
|||
width: 100%; |
|||
} |
|||
|
|||
.dialog-footer { |
|||
display: flex; |
|||
gap: 8px; |
|||
text-align: center; |
|||
} |
|||
|
|||
/* 修复模态框层级问题 - rqrq */ |
|||
::v-deep .el-dialog__wrapper { |
|||
z-index: 2000 !important; |
|||
} |
|||
|
|||
::v-deep .el-overlay { |
|||
z-index: 2000 !important; |
|||
} |
|||
</style> |
|||
@ -0,0 +1,467 @@ |
|||
<template> |
|||
<div> |
|||
<div class="pda-container"> |
|||
<!-- 头部栏 - rqrq --> |
|||
<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="goHome"> |
|||
首页 |
|||
</div> |
|||
</div> |
|||
|
|||
<div class="table-body" style="max-height: 600px; 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="pallet-info-section"> |
|||
<!-- 托盘类型选择 - rqrq --> |
|||
<div class="input-group"> |
|||
<label class="input-label">托盘类型</label> |
|||
<el-select |
|||
v-model="currentPalletType" |
|||
placeholder="请选择托盘类型" |
|||
style="width: 100%;" |
|||
@change="handlePalletTypeChange" |
|||
> |
|||
<el-option |
|||
v-for="type in palletTypeOptions" |
|||
:key="type.palletType" |
|||
:label="`${type.palletType} - ${type.typeDesc}`" |
|||
:value="type.palletType" |
|||
/> |
|||
</el-select> |
|||
</div> |
|||
|
|||
<div class="input-group"> |
|||
<label class="input-label">空托数量</label> |
|||
<el-select v-model="count"> |
|||
<el-option value=1 label=1></el-option> |
|||
<el-option value=2 label=2></el-option> |
|||
<el-option value=3 label=3></el-option> |
|||
<el-option value=4 label=4></el-option> |
|||
<el-option value=5 label=5></el-option> |
|||
<el-option value=6 label=6></el-option> |
|||
</el-select> |
|||
</div> |
|||
|
|||
<!-- 当前站点信息 - rqrq --> |
|||
<div class="info-row"> |
|||
<label class="info-label">当前站点ID:</label> |
|||
<span class="info-value">{{ palletInfo.currentStationId || '-' }}</span> |
|||
</div> |
|||
|
|||
<div class="info-row"> |
|||
<label class="info-label">当前站点编码:</label> |
|||
<span class="info-value">{{ palletInfo.currentStationCode || '-' }}</span> |
|||
</div> |
|||
|
|||
<!-- 操作按钮 - rqrq --> |
|||
<div class="button-row" style="display: flex; gap: 8px; margin-top: 16px;"> |
|||
<button |
|||
class="action-btn primary" |
|||
@click="handleNotifyInbound" |
|||
:disabled="notifyLoading || !currentPalletType" |
|||
style="flex: 1;"> |
|||
{{ notifyLoading ? '处理中...' : '通知入库' }} |
|||
</button> |
|||
<button |
|||
class="action-btn primary" |
|||
@click="handleInboundAndTransport" |
|||
:disabled="transportLoading || !currentPalletType" |
|||
style="flex: 1;"> |
|||
{{ transportLoading ? '处理中...' : '入库并运输' }} |
|||
</button> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
|
|||
<!-- 通知入库口选择弹窗:必须明确选择入库口1/2后才允许提交 - rqrq --> |
|||
<el-dialog |
|||
title="请选择入库口" |
|||
:visible.sync="inboundPortDialogVisible" |
|||
width="90%" |
|||
:close-on-click-modal="false" |
|||
:show-close="false" |
|||
:append-to-body="true" |
|||
> |
|||
<div class="input-group"> |
|||
<label class="input-label">入库口</label> |
|||
<el-select v-model="selectedInboundPort" placeholder="请选择入库口" style="width: 100%;"> |
|||
<el-option |
|||
v-for="option in inboundPortOptions" |
|||
:key="option.value" |
|||
:label="option.label" |
|||
:value="option.value" |
|||
/> |
|||
</el-select> |
|||
</div> |
|||
<div slot="footer" class="dialog-footer"> |
|||
<button class="action-btn secondary" @click="cancelInboundPortDialog">取消</button> |
|||
<button class="action-btn primary" @click="confirmNotifyInbound">确认</button> |
|||
</div> |
|||
</el-dialog> |
|||
</div> |
|||
</template> |
|||
|
|||
<script> |
|||
import { |
|||
checkEmptyPallet, |
|||
getPalletTypes, |
|||
updatePalletTypeAndAutoSort, |
|||
notifyEmptyPalletInbound |
|||
} from '../../../api/haianAutoWarehouse/emptyPalletAssembly' |
|||
|
|||
export default { |
|||
data() { |
|||
return { |
|||
// 海安PDA前端site唯一来源为store用户对象,兼容旧缓存兜底 - rqrq |
|||
site: (this.$store && this.$store.state && this.$store.state.user && this.$store.state.user.site) || localStorage.getItem('site'), |
|||
|
|||
// 托盘信息 - rqrq |
|||
palletCode: '', |
|||
palletScanned: false, |
|||
palletInfo: { |
|||
currentStationId: '', |
|||
currentStationCode: '', |
|||
palletType: '', |
|||
area: '' |
|||
}, |
|||
|
|||
// 托盘类型 - rqrq |
|||
currentPalletType: '', |
|||
palletTypeOptions: [], |
|||
count: 1, |
|||
// 通知入库口选择 - rqrq |
|||
inboundPortDialogVisible: false, |
|||
selectedInboundPort: '', |
|||
inboundPortOptions: [ |
|||
{ label: '入库口1', value: 'INBOUND_PORT_1' }, |
|||
{ label: '入库口2', value: 'INBOUND_PORT_2' } |
|||
], |
|||
// 加载状态 - rqrq |
|||
notifyLoading: false, |
|||
transportLoading: false |
|||
}; |
|||
}, |
|||
methods: { |
|||
// 返回上一页并清空页面状态,避免keep-alive导致脏数据残留 - rqrq |
|||
handleBack() { |
|||
this.resetPage(false); |
|||
this.$router.back(); |
|||
}, |
|||
|
|||
// 回首页前清理状态,保证再次进入页面从干净态开始 - rqrq |
|||
goHome() { |
|||
this.resetPage(false); |
|||
this.$router.push({ path: '/' }); |
|||
}, |
|||
|
|||
// 扫描托盘 - rqrq |
|||
handlePalletScan() { |
|||
if (!this.palletCode.trim()) { |
|||
this.$alert('请输入托盘编码', '提示', { |
|||
confirmButtonText: '确定' |
|||
}); |
|||
return; |
|||
} |
|||
|
|||
checkEmptyPallet({ |
|||
site: this.site, |
|||
palletId: this.palletCode |
|||
}).then(({ data }) => { |
|||
if (data.code === 0) { |
|||
// 后端返回正确的6位栈板码,赋值给输入框 - rqrq |
|||
this.palletCode = data.row.palletId; |
|||
|
|||
// 托盘信息 - rqrq |
|||
this.palletInfo = data.row; |
|||
this.currentPalletType = data.row.palletType || ''; |
|||
this.palletScanned = true; |
|||
|
|||
// 根据托盘的palletFamily加载托盘类型选项 - rqrq |
|||
this.loadPalletTypes(data.row.palletFamily); |
|||
|
|||
} else { |
|||
this.$alert(data.msg || '托盘验证失败', '错误', { |
|||
confirmButtonText: '确定', |
|||
callback: () => { |
|||
this.palletCode = ''; |
|||
this.$nextTick(() => { |
|||
if (this.$refs.palletInput) { |
|||
this.$refs.palletInput.focus(); |
|||
} |
|||
}); |
|||
} |
|||
}); |
|||
} |
|||
}).catch(error => { |
|||
console.error('查询托盘失败:', error); |
|||
this.$alert(error.message || '查询托盘失败', '错误', { |
|||
confirmButtonText: '确定', |
|||
callback: () => { |
|||
this.palletCode = ''; |
|||
this.$nextTick(() => { |
|||
if (this.$refs.palletInput) { |
|||
this.$refs.palletInput.focus(); |
|||
} |
|||
}); |
|||
} |
|||
}); |
|||
}); |
|||
}, |
|||
|
|||
// 加载托盘类型选项(根据palletFamily过滤)- rqrq |
|||
loadPalletTypes(palletFamily) { |
|||
getPalletTypes({ |
|||
site: this.site, |
|||
palletFamily: palletFamily || '' |
|||
}).then(({ data }) => { |
|||
if (data.code === 0) { |
|||
this.palletTypeOptions = data.rows || []; |
|||
} else { |
|||
this.palletTypeOptions = []; |
|||
this.$alert('获取托盘类型失败', '错误', { |
|||
confirmButtonText: '确定' |
|||
}); |
|||
} |
|||
}).catch(error => { |
|||
console.error('获取托盘类型失败:', error); |
|||
this.palletTypeOptions = []; |
|||
}); |
|||
}, |
|||
|
|||
// 托盘类型变更事件 - rqrq |
|||
handlePalletTypeChange() { |
|||
// 保存到数据库 - rqrq |
|||
updatePalletTypeAndAutoSort({ |
|||
site: this.site, |
|||
palletId: this.palletCode, |
|||
palletType: this.currentPalletType, |
|||
autoSort: 'N', |
|||
forceFullPalletOut: false |
|||
}).then(({ data }) => { |
|||
if (data.code === 0) { |
|||
this.$message.success('更新成功'); |
|||
} else { |
|||
this.$alert(data.msg || '更新失败', '错误', { |
|||
confirmButtonText: '确定' |
|||
}); |
|||
} |
|||
}).catch(error => { |
|||
console.error('更新失败:', error); |
|||
this.$alert(error.message || '更新失败', '错误', { |
|||
confirmButtonText: '确定' |
|||
}); |
|||
}); |
|||
}, |
|||
|
|||
// 通知入库 - rqrq |
|||
handleNotifyInbound() { |
|||
if (!this.currentPalletType) { |
|||
this.$alert('请先选择托盘类型', '提示', { |
|||
confirmButtonText: '确定' |
|||
}); |
|||
return; |
|||
} |
|||
// 左按钮“通知入库”必须先选入库口,后端再把入库口映射为固定站点号 - rqrq |
|||
this.selectedInboundPort = ''; |
|||
this.inboundPortDialogVisible = true; |
|||
}, |
|||
|
|||
// 关闭入库口弹窗并清理选择状态,避免上次选择串到本次提交 - rqrq |
|||
cancelInboundPortDialog() { |
|||
this.inboundPortDialogVisible = false; |
|||
this.selectedInboundPort = ''; |
|||
}, |
|||
|
|||
// 确认通知入库:先校验入库口,再调用通知入库接口 - rqrq |
|||
confirmNotifyInbound() { |
|||
if (!this.selectedInboundPort) { |
|||
this.$alert('请选择入库口', '提示', { |
|||
confirmButtonText: '确定' |
|||
}); |
|||
return; |
|||
} |
|||
this.inboundPortDialogVisible = false; |
|||
this.$confirm('确定要执行通知入库操作吗?', '确认操作', { |
|||
confirmButtonText: '确定', |
|||
cancelButtonText: '取消', |
|||
type: 'warning' |
|||
}).then(() => { |
|||
this.notifyLoading = true; |
|||
|
|||
notifyEmptyPalletInbound({ |
|||
site: this.site, |
|||
palletId: this.palletCode, |
|||
transportFlag: 'N', |
|||
count: Number(this.count), |
|||
inboundPort: this.selectedInboundPort, |
|||
}).then(({ data }) => { |
|||
if (data && data.code === 0) { |
|||
this.$message.success('通知入库成功'); |
|||
// 清空页面重新扫描 - rqrq |
|||
this.resetPage(true); |
|||
} else { |
|||
this.$alert(data.msg || '通知入库失败', '错误', { |
|||
confirmButtonText: '确定' |
|||
}); |
|||
} |
|||
}).catch(error => { |
|||
console.error('通知入库失败:', error); |
|||
this.$alert(error.message || '通知入库失败', '错误', { |
|||
confirmButtonText: '确定' |
|||
}); |
|||
}).finally(() => { |
|||
this.notifyLoading = false; |
|||
}); |
|||
}).catch(() => { |
|||
// 用户取消操作,不提交通知入库 - rqrq |
|||
}); |
|||
}, |
|||
|
|||
// 入库并运输 - rqrq |
|||
handleInboundAndTransport() { |
|||
if (!this.currentPalletType) { |
|||
this.$alert('请先选择托盘类型', '提示', { |
|||
confirmButtonText: '确定' |
|||
}); |
|||
return; |
|||
} |
|||
// 右按钮“入库并运输”前置校验:栈板必须绑定area,否则当前位置禁止空托入库 - rqrq |
|||
if (!this.palletInfo.area || !String(this.palletInfo.area).trim()) { |
|||
this.$alert('当前位置不允许空托入库', '提示', { |
|||
confirmButtonText: '确定' |
|||
}); |
|||
return; |
|||
} |
|||
|
|||
this.$confirm('确定要执行入库并运输操作吗?', '确认操作', { |
|||
confirmButtonText: '确定', |
|||
cancelButtonText: '取消', |
|||
type: 'warning' |
|||
}).then(() => { |
|||
this.transportLoading = true; |
|||
|
|||
notifyEmptyPalletInbound({ |
|||
site: this.site, |
|||
palletId: this.palletCode, |
|||
transportFlag: 'Y', |
|||
count: Number(this.count), |
|||
}).then(({ data }) => { |
|||
if (data && data.code === 0) { |
|||
this.$message.success('入库并运输成功'); |
|||
// 清空页面重新扫描 - rqrq |
|||
this.resetPage(true); |
|||
} else { |
|||
this.$alert(data.msg || '入库并运输失败', '错误', { |
|||
confirmButtonText: '确定' |
|||
}); |
|||
} |
|||
}).catch(error => { |
|||
console.error('入库并运输失败:', error); |
|||
this.$alert(error.message || '入库并运输失败', '错误', { |
|||
confirmButtonText: '确定' |
|||
}); |
|||
}).finally(() => { |
|||
this.transportLoading = false; |
|||
}); |
|||
}).catch(() => { |
|||
// 用户取消操作 |
|||
}); |
|||
}, |
|||
|
|||
// 重置页面并按需恢复扫码焦点,统一海安PDA页面生命周期清理行为 - rqrq |
|||
resetPage(needFocus) { |
|||
this.palletCode = ''; |
|||
this.palletScanned = false; |
|||
this.palletInfo = { |
|||
currentStationId: '', |
|||
currentStationCode: '', |
|||
palletType: '', |
|||
area: '' |
|||
}; |
|||
this.currentPalletType = ''; |
|||
this.palletTypeOptions = []; |
|||
this.count = 1; |
|||
this.inboundPortDialogVisible = false; |
|||
this.selectedInboundPort = ''; |
|||
|
|||
if (needFocus) { |
|||
this.$nextTick(() => { |
|||
if (this.$refs.palletInput) { |
|||
this.$refs.palletInput.focus(); |
|||
} |
|||
}); |
|||
} |
|||
} |
|||
}, |
|||
mounted() { |
|||
this.$nextTick(() => { |
|||
if (this.$refs.palletInput) { |
|||
this.$refs.palletInput.focus(); |
|||
} |
|||
}); |
|||
}, |
|||
activated() { |
|||
this.resetPage(true); |
|||
}, |
|||
beforeRouteLeave(to, from, next) { |
|||
this.resetPage(false); |
|||
next(); |
|||
} |
|||
}; |
|||
</script> |
|||
|
|||
<style scoped> |
|||
/* 托盘信息区域 - rqrq */ |
|||
.pallet-info-section { |
|||
margin-top: 16px; |
|||
padding: 12px; |
|||
background: #f5f7fa; |
|||
border-radius: 6px; |
|||
} |
|||
|
|||
.info-row { |
|||
display: flex; |
|||
align-items: center; |
|||
padding: 8px 0; |
|||
border-bottom: 1px solid #e4e7ed; |
|||
} |
|||
|
|||
.info-row:last-child { |
|||
border-bottom: none; |
|||
} |
|||
|
|||
.info-label { |
|||
font-weight: bold; |
|||
color: #606266; |
|||
width: 120px; |
|||
flex-shrink: 0; |
|||
} |
|||
|
|||
.info-value { |
|||
color: #303133; |
|||
font-size: 14px; |
|||
} |
|||
|
|||
.button-row { |
|||
margin-top: 12px; |
|||
} |
|||
</style> |
|||
@ -0,0 +1,596 @@ |
|||
<template> |
|||
<div> |
|||
<div class="pda-container"> |
|||
<!-- 头部栏 - rqrq --> |
|||
<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="goHome"> |
|||
首页 |
|||
</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> |
|||
<div style="display: flex; gap: 8px;"> |
|||
<el-input |
|||
v-model="sourcePalletCode" |
|||
placeholder="请扫描来源托盘编码" |
|||
class="form-input" |
|||
style="flex: 0.7;" |
|||
clearable |
|||
@keyup.enter.native="handleSourcePalletScan" |
|||
@clear="handleSourceClear" |
|||
inputmode="none" |
|||
autocomplete="off" |
|||
autocorrect="off" |
|||
spellcheck="false" |
|||
ref="sourcePalletInput" |
|||
/> |
|||
<button |
|||
class="action-btn secondary" |
|||
style="flex: 0.3; margin: 0;" |
|||
:disabled="!sourceValidated" |
|||
@click="showSourceDetail" |
|||
> |
|||
查看明细 |
|||
</button> |
|||
</div> |
|||
<!-- 来源托盘信息显示 - rqrq --> |
|||
<div v-if="sourceValidated" class="pallet-info"> |
|||
<span class="info-item">类型: {{ sourcePalletType }}{{ sourceTypeDesc ? ' - ' + sourceTypeDesc : '' }}</span> |
|||
<span class="info-item">数量: {{ sourceDetailCount }}</span> |
|||
</div> |
|||
</div> |
|||
|
|||
<!-- 第二行:目标托盘 - rqrq --> |
|||
<div class="input-group"> |
|||
<label class="input-label">目标托盘</label> |
|||
<div style="display: flex; gap: 8px;"> |
|||
<el-input |
|||
v-model="targetPalletCode" |
|||
placeholder="请扫描目标托盘编码" |
|||
class="form-input" |
|||
style="flex: 0.7;" |
|||
clearable |
|||
@keyup.enter.native="handleTargetPalletScan" |
|||
@clear="handleTargetClear" |
|||
inputmode="none" |
|||
autocomplete="off" |
|||
autocorrect="off" |
|||
spellcheck="false" |
|||
ref="targetPalletInput" |
|||
/> |
|||
<button |
|||
class="action-btn secondary" |
|||
style="flex: 0.3; margin: 0;" |
|||
:disabled="!targetValidated" |
|||
@click="showTargetDetail" |
|||
> |
|||
查看明细 |
|||
</button> |
|||
</div> |
|||
<!-- 目标托盘信息显示 - rqrq --> |
|||
<div v-if="targetValidated" class="pallet-info"> |
|||
<span class="info-item">类型: {{ targetPalletType }}{{ targetTypeDesc ? ' - ' + targetTypeDesc : '' }}</span> |
|||
<span class="info-item">数量: {{ targetDetailCount }}</span> |
|||
</div> |
|||
</div> |
|||
|
|||
<!-- 第三行:操作按钮 - rqrq --> |
|||
<div class="input-group" style="margin-top: 20px;"> |
|||
<button |
|||
class="action-btn primary full-width" |
|||
:disabled="!canMerge || mergeLoading" |
|||
@click="handleMerge" |
|||
> |
|||
{{ mergeLoading ? '合托中...' : '合托' }} |
|||
</button> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
|
|||
<!-- 查看明细弹窗 - rqrq --> |
|||
<el-dialog |
|||
:title="detailDialogTitle" |
|||
:visible.sync="detailDialogVisible" |
|||
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: 300px; overflow-y: auto;"> |
|||
<div class="detail-table"> |
|||
<div class="table-header"> |
|||
<div class="col-seq">序号</div> |
|||
<div class="col-partno">物料</div> |
|||
<div class="col-serial">条码号</div> |
|||
</div> |
|||
<div |
|||
v-for="(detail, index) in currentDetailList" |
|||
:key="index" |
|||
class="table-row" |
|||
> |
|||
<div class="col-seq">{{ index + 1 }}</div> |
|||
<div class="col-partno">{{ detail.partNo }}</div> |
|||
<div class="col-serial">{{ detail.serialNo }}</div> |
|||
</div> |
|||
<!-- 暂无数据提示 - rqrq --> |
|||
<div v-if="currentDetailList.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="detailDialogVisible=false">关闭</button> |
|||
</div> |
|||
</el-dialog> |
|||
</div> |
|||
</template> |
|||
|
|||
<script> |
|||
import { |
|||
checkPalletForMerge, |
|||
checkTargetPalletType, |
|||
getPalletDetailForMerge, |
|||
executePalletMerge |
|||
} from '../../../api/haianAutoWarehouse/palletMerge' |
|||
|
|||
export default { |
|||
data() { |
|||
return { |
|||
// 海安PDA前端site唯一来源为store用户对象,兼容旧缓存兜底 - rqrq |
|||
site: (this.$store && this.$store.state && this.$store.state.user && this.$store.state.user.site) || localStorage.getItem('site'), |
|||
|
|||
// 来源托盘 - rqrq |
|||
sourcePalletCode: '', |
|||
sourceValidated: false, |
|||
sourcePalletType: '', |
|||
sourceTypeDesc: '', |
|||
sourceDetailCount: 0, |
|||
sourceDetailList: [], |
|||
|
|||
// 目标托盘 - rqrq |
|||
targetPalletCode: '', |
|||
targetValidated: false, |
|||
targetPalletType: '', |
|||
targetTypeDesc: '', |
|||
targetDetailCount: 0, |
|||
targetDetailList: [], |
|||
|
|||
// 明细弹窗 - rqrq |
|||
detailDialogVisible: false, |
|||
detailDialogTitle: '', |
|||
currentDetailList: [], |
|||
|
|||
// 合托按钮loading - rqrq |
|||
mergeLoading: false |
|||
} |
|||
}, |
|||
computed: { |
|||
// 是否可以合托:两个托盘都校验通过 - rqrq |
|||
canMerge() { |
|||
return this.sourceValidated && this.targetValidated |
|||
} |
|||
}, |
|||
methods: { |
|||
// 返回上一页并清空页面状态,避免keep-alive导致脏数据残留 - rqrq |
|||
handleBack() { |
|||
this.resetPage(false) |
|||
this.$router.back() |
|||
}, |
|||
|
|||
// 回首页前清理状态,保证再次进入页面从干净态开始 - rqrq |
|||
goHome() { |
|||
this.resetPage(false) |
|||
this.$router.push({ path: '/' }) |
|||
}, |
|||
|
|||
// 处理扫描输入(去掉所有空格)- rqrq |
|||
processScanInput(input) { |
|||
if (input) { |
|||
// 去掉所有空格(包括中间的空格)- rqrq |
|||
return input.replace(/\s+/g, '') |
|||
} |
|||
return input |
|||
}, |
|||
|
|||
// 来源托盘扫描 - rqrq |
|||
handleSourcePalletScan() { |
|||
// 去掉所有空格 - rqrq |
|||
const scannedCode = this.processScanInput(this.sourcePalletCode) |
|||
if (!scannedCode) { |
|||
this.$alert('请输入来源托盘编码', '错误', { confirmButtonText: '确定' }) |
|||
return |
|||
} |
|||
|
|||
// 校验来源托盘(后台会处理LR并返回真实托盘号)- rqrq |
|||
checkPalletForMerge({ |
|||
site: this.site, |
|||
palletId: scannedCode |
|||
}).then(({ data }) => { |
|||
if (data && data.code === 0) { |
|||
// 使用后台返回的真实托盘号更新输入框 - rqrq |
|||
this.sourcePalletCode = data.palletId || scannedCode |
|||
this.sourceValidated = true |
|||
this.sourcePalletType = data.palletType || '' |
|||
this.sourceTypeDesc = data.typeDesc || '' |
|||
|
|||
// 查询来源托盘明细 - rqrq |
|||
this.loadSourceDetail() |
|||
|
|||
// 聚焦到目标托盘输入框 - rqrq |
|||
this.$nextTick(() => { |
|||
if (this.$refs.targetPalletInput) { |
|||
this.$refs.targetPalletInput.focus() |
|||
} |
|||
}) |
|||
} else { |
|||
this.handleSourceError(data.msg || '来源托盘校验失败') |
|||
} |
|||
}).catch(error => { |
|||
console.error('来源托盘校验失败:', error) |
|||
this.handleSourceError(error.message || '来源托盘校验失败') |
|||
}) |
|||
}, |
|||
|
|||
// 加载来源托盘明细 - rqrq |
|||
loadSourceDetail() { |
|||
getPalletDetailForMerge({ |
|||
site: this.site, |
|||
palletId: this.sourcePalletCode |
|||
}).then(({ data }) => { |
|||
if (data && data.code === 0) { |
|||
this.sourceDetailList = data.rows || [] |
|||
this.sourceDetailCount = this.sourceDetailList.length |
|||
} else { |
|||
this.sourceDetailList = [] |
|||
this.sourceDetailCount = 0 |
|||
} |
|||
}).catch(error => { |
|||
console.error('查询来源托盘明细失败:', error) |
|||
this.sourceDetailList = [] |
|||
this.sourceDetailCount = 0 |
|||
}) |
|||
}, |
|||
|
|||
// 来源托盘校验失败处理 - rqrq |
|||
handleSourceError(errorMsg) { |
|||
if (errorMsg.length > 100) { |
|||
errorMsg = errorMsg.substring(0, 100) + '...' |
|||
} |
|||
this.$alert(errorMsg, '错误', { |
|||
confirmButtonText: '确定', |
|||
callback: () => { |
|||
this.handleSourceClear() |
|||
this.$nextTick(() => { |
|||
if (this.$refs.sourcePalletInput) { |
|||
this.$refs.sourcePalletInput.focus() |
|||
} |
|||
}) |
|||
} |
|||
}) |
|||
}, |
|||
|
|||
// 清空来源托盘 - rqrq |
|||
handleSourceClear() { |
|||
this.sourcePalletCode = '' |
|||
this.sourceValidated = false |
|||
this.sourcePalletType = '' |
|||
this.sourceTypeDesc = '' |
|||
this.sourceDetailCount = 0 |
|||
this.sourceDetailList = [] |
|||
}, |
|||
|
|||
// 目标托盘扫描 - rqrq |
|||
handleTargetPalletScan() { |
|||
// 去掉所有空格 - rqrq |
|||
const scannedCode = this.processScanInput(this.targetPalletCode) |
|||
if (!scannedCode) { |
|||
this.$alert('请输入目标托盘编码', '错误', { confirmButtonText: '确定' }) |
|||
return |
|||
} |
|||
|
|||
// 先校验目标托盘是否存在(后台会处理LR并返回真实托盘号)- rqrq |
|||
checkPalletForMerge({ |
|||
site: this.site, |
|||
palletId: scannedCode |
|||
}).then(({ data }) => { |
|||
if (data && data.code === 0) { |
|||
// 使用后台返回的真实托盘号 - rqrq |
|||
const realPalletId = data.palletId || scannedCode |
|||
const palletType = data.palletType || '' |
|||
const typeDesc = data.typeDesc || '' |
|||
|
|||
// 不能和来源托盘相同(使用真实托盘号比较)- rqrq |
|||
if (this.sourcePalletCode && realPalletId === this.sourcePalletCode) { |
|||
this.$alert('目标托盘不能与来源托盘相同', '错误', { confirmButtonText: '确定' }) |
|||
this.targetPalletCode = '' |
|||
return |
|||
} |
|||
|
|||
// 再校验目标托盘是否为混装托盘(wcs_auto_sort = 'N')- rqrq |
|||
checkTargetPalletType({ |
|||
site: this.site, |
|||
palletType: palletType |
|||
}).then(({ data: typeData }) => { |
|||
if (typeData && typeData.code === 0) { |
|||
// 更新输入框为真实托盘号 - rqrq |
|||
this.targetPalletCode = realPalletId |
|||
this.targetValidated = true |
|||
this.targetPalletType = palletType |
|||
this.targetTypeDesc = typeDesc |
|||
|
|||
// 查询目标托盘明细 - rqrq |
|||
this.loadTargetDetail() |
|||
|
|||
this.$message.success('目标托盘校验通过') |
|||
} else { |
|||
this.handleTargetError(typeData.msg || '目标栈板必须是混装托盘才能合托') |
|||
} |
|||
}).catch(error => { |
|||
console.error('目标托盘类型校验失败:', error) |
|||
this.handleTargetError('目标栈板必须是混装托盘才能合托') |
|||
}) |
|||
} else { |
|||
this.handleTargetError(data.msg || '目标托盘校验失败') |
|||
} |
|||
}).catch(error => { |
|||
console.error('目标托盘校验失败:', error) |
|||
this.handleTargetError(error.message || '目标托盘校验失败') |
|||
}) |
|||
}, |
|||
|
|||
// 加载目标托盘明细 - rqrq |
|||
loadTargetDetail() { |
|||
getPalletDetailForMerge({ |
|||
site: this.site, |
|||
palletId: this.targetPalletCode |
|||
}).then(({ data }) => { |
|||
if (data && data.code === 0) { |
|||
this.targetDetailList = data.rows || [] |
|||
this.targetDetailCount = this.targetDetailList.length |
|||
} else { |
|||
this.targetDetailList = [] |
|||
this.targetDetailCount = 0 |
|||
} |
|||
}).catch(error => { |
|||
console.error('查询目标托盘明细失败:', error) |
|||
this.targetDetailList = [] |
|||
this.targetDetailCount = 0 |
|||
}) |
|||
}, |
|||
|
|||
// 目标托盘校验失败处理 - rqrq |
|||
handleTargetError(errorMsg) { |
|||
if (errorMsg.length > 100) { |
|||
errorMsg = errorMsg.substring(0, 100) + '...' |
|||
} |
|||
this.$alert(errorMsg, '错误', { |
|||
confirmButtonText: '确定', |
|||
callback: () => { |
|||
this.handleTargetClear() |
|||
this.$nextTick(() => { |
|||
if (this.$refs.targetPalletInput) { |
|||
this.$refs.targetPalletInput.focus() |
|||
} |
|||
}) |
|||
} |
|||
}) |
|||
}, |
|||
|
|||
// 清空目标托盘 - rqrq |
|||
handleTargetClear() { |
|||
this.targetPalletCode = '' |
|||
this.targetValidated = false |
|||
this.targetPalletType = '' |
|||
this.targetTypeDesc = '' |
|||
this.targetDetailCount = 0 |
|||
this.targetDetailList = [] |
|||
}, |
|||
|
|||
// 查看来源托盘明细 - rqrq |
|||
showSourceDetail() { |
|||
this.detailDialogTitle = `来源托盘明细 (${this.sourcePalletCode})` |
|||
this.currentDetailList = this.sourceDetailList |
|||
this.detailDialogVisible = true |
|||
}, |
|||
|
|||
// 查看目标托盘明细 - rqrq |
|||
showTargetDetail() { |
|||
this.detailDialogTitle = `目标托盘明细 (${this.targetPalletCode})` |
|||
this.currentDetailList = this.targetDetailList |
|||
this.detailDialogVisible = true |
|||
}, |
|||
|
|||
// 执行合托 - rqrq |
|||
handleMerge() { |
|||
if (!this.canMerge) { |
|||
this.$alert('请先扫描来源托盘和目标托盘', '错误', { confirmButtonText: '确定' }) |
|||
return |
|||
} |
|||
|
|||
// 确认对话框 - rqrq |
|||
this.$confirm( |
|||
`确定将来源托盘【${this.sourcePalletCode}】的${this.sourceDetailCount}条物料转移到目标托盘【${this.targetPalletCode}】吗?`, |
|||
'合托确认', |
|||
{ |
|||
confirmButtonText: '确定', |
|||
cancelButtonText: '取消', |
|||
type: 'warning' |
|||
} |
|||
).then(() => { |
|||
this.doMerge() |
|||
}).catch(() => { |
|||
// 用户取消 - rqrq |
|||
}) |
|||
}, |
|||
|
|||
// 执行合托操作 - rqrq |
|||
doMerge() { |
|||
this.mergeLoading = true |
|||
|
|||
executePalletMerge({ |
|||
site: this.site, |
|||
sourcePalletId: this.sourcePalletCode, |
|||
targetPalletId: this.targetPalletCode |
|||
}).then(({ data }) => { |
|||
if (data && data.code === 0) { |
|||
this.$message.success('合托成功') |
|||
// 重置页面 - rqrq |
|||
this.resetPage(true) |
|||
} else { |
|||
this.$alert(data.msg || '合托失败', '错误', { |
|||
confirmButtonText: '确定' |
|||
}) |
|||
} |
|||
}).catch(error => { |
|||
console.error('合托失败:', error) |
|||
this.$alert(error.message || '合托失败', '错误', { |
|||
confirmButtonText: '确定' |
|||
}) |
|||
}).finally(() => { |
|||
this.mergeLoading = false |
|||
}) |
|||
}, |
|||
|
|||
// 重置页面并按需恢复扫码焦点,统一海安PDA页面生命周期清理行为 - rqrq |
|||
resetPage(needFocus) { |
|||
this.handleSourceClear() |
|||
this.handleTargetClear() |
|||
this.detailDialogVisible = false |
|||
this.detailDialogTitle = '' |
|||
this.currentDetailList = [] |
|||
|
|||
if (needFocus) { |
|||
this.$nextTick(() => { |
|||
if (this.$refs.sourcePalletInput) { |
|||
this.$refs.sourcePalletInput.focus() |
|||
} |
|||
}) |
|||
} |
|||
} |
|||
}, |
|||
mounted() { |
|||
// 页面加载后聚焦到来源托盘输入框 - rqrq |
|||
this.$nextTick(() => { |
|||
if (this.$refs.sourcePalletInput) { |
|||
this.$refs.sourcePalletInput.focus() |
|||
} |
|||
}) |
|||
}, |
|||
activated() { |
|||
this.resetPage(true) |
|||
}, |
|||
beforeRouteLeave(to, from, next) { |
|||
this.resetPage(false) |
|||
next() |
|||
} |
|||
} |
|||
</script> |
|||
|
|||
<style scoped> |
|||
/* 托盘信息显示 - rqrq */ |
|||
.pallet-info { |
|||
display: flex; |
|||
gap: 16px; |
|||
margin-top: 8px; |
|||
padding: 8px 12px; |
|||
background-color: #f0f9eb; |
|||
border-radius: 4px; |
|||
font-size: 13px; |
|||
color: #67c23a; |
|||
} |
|||
|
|||
.info-item { |
|||
font-weight: bold; |
|||
} |
|||
|
|||
/* 全宽按钮 - rqrq */ |
|||
.full-width { |
|||
width: 100%; |
|||
height: 48px; |
|||
font-size: 18px; |
|||
font-weight: bold; |
|||
} |
|||
|
|||
/* 表格样式 - rqrq */ |
|||
.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-seq { |
|||
flex: 0.5; |
|||
text-align: center; |
|||
} |
|||
|
|||
.col-partno { |
|||
flex: 2; |
|||
text-align: center; |
|||
word-break: break-all; |
|||
} |
|||
|
|||
.col-serial { |
|||
flex: 3; |
|||
text-align: center; |
|||
word-break: break-all; |
|||
} |
|||
|
|||
/* 空数据提示 - rqrq */ |
|||
.empty-hint { |
|||
text-align: center; |
|||
color: #999; |
|||
padding: 20px; |
|||
width: 100%; |
|||
} |
|||
|
|||
.empty-row { |
|||
justify-content: center; |
|||
} |
|||
|
|||
/* 弹窗底部按钮 - rqrq */ |
|||
.dialog-footer { |
|||
text-align: center; |
|||
} |
|||
|
|||
/* 按钮禁用状态样式 - rqrq */ |
|||
.action-btn:disabled { |
|||
opacity: 0.6; |
|||
cursor: not-allowed; |
|||
background-color: #ccc !important; |
|||
border-color: #ccc !important; |
|||
} |
|||
</style> |
|||
Write
Preview
Loading…
Cancel
Save
Reference in new issue