Browse Source

合托功能

master
常熟吴彦祖 1 month ago
parent
commit
79bfb0a6fb
  1. 16
      src/api/automatedWarehouse/palletMerge.js
  2. 1
      src/router/index.js
  3. 6
      src/views/main.vue
  4. 578
      src/views/modules/automatedWarehouse/palletMerge.vue

16
src/api/automatedWarehouse/palletMerge.js

@ -0,0 +1,16 @@
import { createAPI } from "@/utils/httpRequest.js";
// ========== 合托相关 ========== - rqrq
// 校验栈板(通用,用于来源/目标托盘)- rqrq
export const checkPalletForMerge = data => createAPI(`/wcsIntegration/checkPalletForMerge`, 'post', data)
// 校验目标栈板是否为混装托盘 - rqrq
export const checkTargetPalletType = data => createAPI(`/wcsIntegration/checkTargetPalletType`, 'post', data)
// 查询栈板明细(根据site+palletId查询pallet_detail)- rqrq
export const getPalletDetailForMerge = data => createAPI(`/wcsIntegration/getPalletDetailForMerge`, 'post', data)
// 执行合托操作(将来源栈板的物料转移到目标栈板)- rqrq
export const executePalletMerge = data => createAPI(`/wcsIntegration/executePalletMerge`, 'post', data)

1
src/router/index.js

@ -140,6 +140,7 @@ const globalRoutes = [
{path: "/cancelWcsPallet",name: "cancelWcsPallet", component: resolve => require(["@/views/modules/automatedWarehouse/cancelWcsPallet.vue"], resolve), meta: { transition: 'instant' ,preload: true,keepAlive: true}},
{path: "/callOutToStation",name: "callOutToStation", component: resolve => require(["@/views/modules/automatedWarehouse/callOutToStation.vue"], resolve), meta: { transition: 'instant' ,preload: true,keepAlive: true}},
{path: "/palletSortingNoAgv",name: "palletSortingNoAgv", component: resolve => require(["@/views/modules/automatedWarehouse/palletSortingNoAgv.vue"], resolve), meta: { transition: 'instant' ,preload: true,keepAlive: true}},
{path: "/palletMerge",name: "palletMerge", component: resolve => require(["@/views/modules/automatedWarehouse/palletMerge.vue"], resolve), meta: { transition: 'instant' ,preload: true,keepAlive: true}},
]

6
src/views/main.vue

@ -167,6 +167,12 @@
</div>
<div class="menu-text">取消组盘</div>
</div>
<div class="menu-item" @click="navigateWithWarehouseCheck('palletMerge')">
<div class="menu-icon purchase">
<van-icon name="shopping-cart-o" size="24" />
</div>
<div class="menu-text">栈板合托</div>
</div>
</div>
</div>
<div class="section">

578
src/views/modules/automatedWarehouse/palletMerge.vue

@ -0,0 +1,578 @@
<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="$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>
<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/automatedWarehouse/palletMerge'
export default {
data() {
return {
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: {
// - rqrq
handleBack() {
this.$router.back()
},
// R/L- rqrq
processPalletCode(palletCode) {
if (palletCode && palletCode.length > 0) {
const lastChar = palletCode.charAt(palletCode.length - 1)
if (lastChar === 'R' || lastChar === 'L' || lastChar === 'r' || lastChar === 'l') {
return palletCode.substring(0, palletCode.length - 1)
}
}
return palletCode
},
// - rqrq
handleSourcePalletScan() {
if (!this.sourcePalletCode.trim()) {
this.$message.error('请输入来源托盘编码')
return
}
// - rqrq
const processedCode = this.processPalletCode(this.sourcePalletCode.trim())
this.sourcePalletCode = processedCode
// - rqrq
checkPalletForMerge({
site: this.site,
palletId: processedCode
}).then(({ data }) => {
if (data && data.code === 0) {
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() {
if (!this.targetPalletCode.trim()) {
this.$message.error('请输入目标托盘编码')
return
}
// - rqrq
const processedCode = this.processPalletCode(this.targetPalletCode.trim())
this.targetPalletCode = processedCode
// - rqrq
if (this.sourcePalletCode && processedCode === this.sourcePalletCode) {
this.$message.error('目标托盘不能与来源托盘相同')
this.targetPalletCode = ''
return
}
// - rqrq
checkPalletForMerge({
site: this.site,
palletId: processedCode
}).then(({ data }) => {
if (data && data.code === 0) {
const palletType = data.palletType || ''
const typeDesc = data.typeDesc || ''
// wcs_auto_sort = 'N'- rqrq
checkTargetPalletType({
site: this.site,
palletType: palletType
}).then(({ data: typeData }) => {
if (typeData && typeData.code === 0) {
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.$message.error('请先扫描来源托盘和目标托盘')
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()
} else {
this.$alert(data.msg || '合托失败', '错误', {
confirmButtonText: '确定'
})
}
}).catch(error => {
console.error('合托失败:', error)
this.$alert(error.message || '合托失败', '错误', {
confirmButtonText: '确定'
})
}).finally(() => {
this.mergeLoading = false
})
},
// - rqrq
resetPage() {
this.handleSourceClear()
this.handleTargetClear()
// - rqrq
this.$nextTick(() => {
if (this.$refs.sourcePalletInput) {
this.$refs.sourcePalletInput.focus()
}
})
}
},
mounted() {
// - rqrq
this.$nextTick(() => {
if (this.$refs.sourcePalletInput) {
this.$refs.sourcePalletInput.focus()
}
})
}
}
</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>
Loading…
Cancel
Save