Browse Source

运输栈板

dev
常熟吴彦祖 14 hours ago
parent
commit
b74e4fb9be
  1. 12
      src/api/haianAutoWarehouse/cancelWcsPallet.js
  2. 15
      src/api/haianAutoWarehouse/emptyPalletAssembly.js
  3. 15
      src/api/haianAutoWarehouse/palletMerge.js
  4. 3
      src/router/index.js
  5. 18
      src/views/main.vue
  6. 516
      src/views/modules/haianAutoWarehouse/haianCancelWcsPallet.vue
  7. 467
      src/views/modules/haianAutoWarehouse/haianEmptyPalletAssembly.vue
  8. 596
      src/views/modules/haianAutoWarehouse/haianPalletMerge.vue

12
src/api/haianAutoWarehouse/cancelWcsPallet.js

@ -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)

15
src/api/haianAutoWarehouse/emptyPalletAssembly.js

@ -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)

15
src/api/haianAutoWarehouse/palletMerge.js

@ -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)

3
src/router/index.js

@ -154,6 +154,9 @@ const globalRoutes = [
{path: "/haianPalletSorting",name: "haianPalletSorting", component: resolve => require(["@/views/modules/haianAutoWarehouse/haianPalletSorting.vue"], resolve), meta: { transition: 'instant' ,preload: true,keepAlive: true}},
{path: "/haianPalletSearch",name: "haianPalletSearch", component: resolve => require(["@/views/modules/haianAutoWarehouse/haianPalletSearch.vue"], resolve), meta: { transition: 'instant' ,preload: true,keepAlive: true}},
{path: "/haianPalletChangeStation",name: "haianPalletChangeStation", component: resolve => require(["@/views/modules/haianAutoWarehouse/haianPalletChangeStation.vue"], resolve), meta: { transition: 'instant' ,preload: true,keepAlive: true}},
{path: "/haianEmptyPalletAssembly",name: "haianEmptyPalletAssembly", component: resolve => require(["@/views/modules/haianAutoWarehouse/haianEmptyPalletAssembly.vue"], resolve), meta: { transition: 'instant' ,preload: true,keepAlive: true}},
{path: "/haianCancelWcsPallet",name: "haianCancelWcsPallet", component: resolve => require(["@/views/modules/haianAutoWarehouse/haianCancelWcsPallet.vue"], resolve), meta: { transition: 'instant' ,preload: true,keepAlive: true}},
{path: "/haianPalletMerge",name: "haianPalletMerge", component: resolve => require(["@/views/modules/haianAutoWarehouse/haianPalletMerge.vue"], resolve), meta: { transition: 'instant' ,preload: true,keepAlive: true}},
]

18
src/views/main.vue

@ -157,6 +157,24 @@
</div>
<div class="menu-text">海安托盘运输</div>
</div>
<div class="menu-item" v-site-auth="'54'" @click="navigateWithWarehouseCheck('haianEmptyPalletAssembly')">
<div class="menu-icon purchase">
<van-icon name="shopping-cart-o" size="24" />
</div>
<div class="menu-text">海安空托盘入库</div>
</div>
<div class="menu-item" v-site-auth="'54'" @click="navigateWithWarehouseCheck('haianCancelWcsPallet')">
<div class="menu-icon purchase">
<van-icon name="shopping-cart-o" size="24" />
</div>
<div class="menu-text">海安取消组盘</div>
</div>
<div class="menu-item" v-site-auth="'54'" @click="navigateWithWarehouseCheck('haianPalletMerge')">
<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" v-site-auth="'55'">

516
src/views/modules/haianAutoWarehouse/haianCancelWcsPallet.vue

@ -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 {
// PDAsitestore - 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
// canOperateshowCancelButton- rqrq
this.showCancelButton = data.row.canOperate === 'Y';
// isEmptyshowRemoveAllButton- 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>

467
src/views/modules/haianAutoWarehouse/haianEmptyPalletAssembly.vue

@ -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 {
// PDAsitestore - 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>

596
src/views/modules/haianAutoWarehouse/haianPalletMerge.vue

@ -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 {
// PDAsitestore - 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>
Loading…
Cancel
Save