<template>
|
<div class="OutboundPicking-container">
|
<div class="page-header">
|
<el-page-header @back="goBack">
|
<template #content>
|
<span class="title">出库拣选确认 - {{ this.$route.query.orderNo }}</span>
|
</template>
|
</el-page-header>
|
</div>
|
<!-- 扫码区域 -->
|
<div class="scanner-area">
|
<el-card>
|
<div class="scanner-form">
|
<el-input
|
ref="palletInput"
|
v-model="scanData.palletCode"
|
placeholder="扫描托盘码"
|
@change="onPalletScan"
|
@keyup.enter.native="onPalletScan">
|
</el-input>
|
<el-input
|
ref="barcodeInput"
|
v-model="scanData.barcode"
|
placeholder="扫描物料条码"
|
@change="onBarcodeScan"
|
@keyup.enter.native="onBarcodeScan">
|
</el-input>
|
<el-button type="success" @click="confirmPicking">确认拣选</el-button>
|
<!-- <el-button type="warning" @click="openSplitDialog">拆包</el-button>
|
<el-button type="info" @click="openRevertSplitDialog">撤销拆包</el-button> -->
|
|
<el-button type="primary" @click="openBatchReturnDialog">回库</el-button>
|
<!-- <el-button type="danger" @click="handleDirectOutbound">直接出库</el-button> -->
|
|
</div>
|
</el-card>
|
</div>
|
|
<!-- 汇总信息 -->
|
<div class="summary-area">
|
<el-card>
|
<div class="summary-info">
|
<el-tag type="warning">未拣选条数: {{summary.unpickedCount}}</el-tag>
|
<el-tag type="danger">未拣选数量: {{summary.unpickedQuantity}}</el-tag>
|
<!-- <el-tag type="success">已拣选条数: {{summary.pickedCount}}</el-tag> -->
|
<el-tag type="info">托盘状态: {{palletStatus}}</el-tag>
|
</div>
|
</el-card>
|
</div>
|
|
<!-- 数据列表 -->
|
<div class="content-area">
|
<el-row :gutter="20">
|
<el-col :span="12">
|
<el-card header="未拣选列表">
|
<el-table :data="unpickedList" border height="440">
|
<el-table-column prop="materielCode" label="物料编码" width="120"></el-table-column>
|
|
<el-table-column prop="assignQuantity" label="分配数量" width="100"></el-table-column>
|
<el-table-column prop="remainQuantity" label="剩余数量" width="100"></el-table-column>
|
<el-table-column prop="locationCode" label="货位" width="100"></el-table-column>
|
<el-table-column prop="currentBarcode" label="条码"></el-table-column>
|
<!-- <el-table-column label="操作" width="100">
|
<template slot-scope="scope">
|
<el-button
|
size="mini"
|
type="primary"
|
@click="handleSingleReturn(scope.row)">
|
回库
|
</el-button>
|
</template>
|
</el-table-column> -->
|
</el-table>
|
</el-card>
|
</el-col>
|
|
<el-col :span="12">
|
<el-card header="已拣选列表">
|
<div class="table-actions">
|
<el-button
|
size="mini"
|
type="danger"
|
:disabled="selectedPickedRows.length === 0"
|
@click="batchCancelSelected">
|
取消拣选
|
</el-button>
|
<span class="selection-count">已选择 {{selectedPickedRows.length}} 项</span>
|
</div>
|
<el-table :data="pickedList" border height="400" style="width: 100%" @selection-change="handlePickedSelectionChange">
|
<el-table-column type="selection" width="55"></el-table-column>
|
<el-table-column prop="materielCode" label="物料编码" width="120"></el-table-column>
|
|
<el-table-column prop="pickedQty" label="已拣数量" width="100"></el-table-column>
|
<el-table-column prop="locationCode" label="货位" width="100"></el-table-column>
|
<el-table-column prop="currentBarcode" label="条码"></el-table-column>
|
|
|
</el-table>
|
</el-card>
|
</el-col>
|
</el-row>
|
</div>
|
|
<!-- 拆包弹窗 -->
|
<!-- 拆包弹窗 -->
|
<div v-if="showCustomSplitDialog" class="custom-dialog-overlay">
|
<div class="custom-dialog-wrapper">
|
<div class="custom-dialog">
|
<div class="custom-dialog-header">
|
<h3>拆包操作</h3>
|
<!-- <el-button
|
type="text"
|
icon="el-icon-close"
|
@click="closeCustomSplitDialog"
|
class="close-button">
|
</el-button> -->
|
<el-button
|
type="text"
|
@click="closeCustomSplitDialog"
|
class="close-button">
|
X
|
</el-button>
|
|
</div>
|
<div class="custom-dialog-body">
|
<el-form :model="splitForm" :rules="splitFormRules" ref="splitFormRef" label-width="100px">
|
<el-form-item label="订单编号">
|
<el-input v-model="splitForm.orderNo" disabled></el-input>
|
</el-form-item>
|
<el-form-item label="托盘编号">
|
<el-input v-model="splitForm.palletCode" disabled></el-input>
|
</el-form-item>
|
<el-form-item label="原条码" prop="originalBarcode">
|
<el-input
|
v-model="splitForm.originalBarcode"
|
placeholder="扫描原条码"
|
@keyup.enter.native="onSplitBarcodeScan"
|
@change="onSplitBarcodeScan"
|
clearable>
|
</el-input>
|
</el-form-item>
|
<el-form-item label="物料编码">
|
<el-input v-model="splitForm.materielCode" disabled></el-input>
|
</el-form-item>
|
<el-form-item label="剩余数量">
|
<el-input v-model="splitForm.maxQuantity" disabled></el-input>
|
</el-form-item>
|
<el-form-item label="拆包数量" prop="splitQuantity">
|
<el-input-number
|
v-model="splitForm.splitQuantity"
|
:min="1"
|
:max="splitForm.maxQuantity"
|
:precision="2"
|
:step="1"
|
style="width: 100%">
|
</el-input-number>
|
</el-form-item>
|
</el-form>
|
</div>
|
<div class="custom-dialog-footer">
|
<el-button @click="closeCustomSplitDialog">取消</el-button>
|
<el-button type="primary" @click="handleSplitPackage" :loading="splitLoading">确认拆包</el-button>
|
</div>
|
</div>
|
</div>
|
</div>
|
|
|
<!-- 撤销拆包弹窗 -->
|
<div v-if="showRevertSplitDialog" class="custom-dialog-overlay">
|
<div class="custom-dialog-wrapper">
|
<div class="custom-dialog">
|
<div class="custom-dialog-header">
|
<h3>撤销拆包</h3>
|
<el-button
|
type="text"
|
@click="closeRevertSplitDialog"
|
class="close-button">
|
×
|
</el-button>
|
</div>
|
<div class="custom-dialog-body">
|
<el-form
|
:model="revertSplitForm"
|
:rules="revertSplitFormRules"
|
ref="revertSplitFormRef"
|
label-width="100px">
|
<el-form-item label="原条码" prop="originalBarcode">
|
<el-input
|
v-model="revertSplitForm.originalBarcode"
|
placeholder="扫描原条码"
|
@keyup.enter.native="onRevertSplitBarcodeScan"
|
@change="onRevertSplitBarcodeScan"
|
clearable>
|
</el-input>
|
</el-form-item>
|
</el-form>
|
</div>
|
<div class="custom-dialog-footer">
|
<el-button @click="closeRevertSplitDialog">取消</el-button>
|
<el-button type="primary" @click="handleRevertSplit" :loading="revertSplitLoading">确认撤销</el-button>
|
</div>
|
</div>
|
</div>
|
</div>
|
|
<!-- 批量回库弹窗 -->
|
<div v-if="showBatchReturnDialog" class="custom-dialog-overlay">
|
<div class="custom-dialog-wrapper">
|
<div class="custom-dialog">
|
<div class="custom-dialog-header">
|
<h3>回库</h3>
|
<el-button
|
type="text"
|
@click="closeBatchReturnDialog"
|
class="close-button">
|
×
|
</el-button>
|
</div>
|
<div class="custom-dialog-body">
|
<el-form
|
:model="batchReturnForm"
|
:rules="batchReturnFormRules"
|
ref="batchReturnFormRef"
|
label-width="100px">
|
<el-form-item label="订单编号">
|
<el-input v-model="batchReturnForm.orderNo" disabled></el-input>
|
</el-form-item>
|
<el-form-item label="托盘编号" prop="palletCode">
|
<el-input
|
v-model="batchReturnForm.palletCode"
|
placeholder="扫描托盘码"
|
@keyup.enter.native="onBatchReturnPalletScan"
|
@change="onBatchReturnPalletScan"
|
clearable>
|
</el-input>
|
</el-form-item>
|
<el-form-item label="未拣选数量">
|
<el-input v-model="batchReturnForm.unpickedCount" disabled></el-input>
|
</el-form-item>
|
<el-form-item label="未拣选条数">
|
<el-input v-model="batchReturnForm.unpickedQuantity" disabled></el-input>
|
</el-form-item>
|
</el-form>
|
</div>
|
<div class="custom-dialog-footer">
|
<el-button @click="closeBatchReturnDialog">取消</el-button>
|
<el-button type="primary" @click="handleBatchReturnConfirm" :loading="batchReturnLoading">确认回库</el-button>
|
</div>
|
</div>
|
</div>
|
</div>
|
<!-- 直接出库弹窗 -->
|
<div v-if="showDirectOutDialog" class="custom-dialog-overlay">
|
<div class="custom-dialog-wrapper">
|
<div class="custom-dialog">
|
<div class="custom-dialog-header">
|
<h3>直接出库</h3>
|
<el-button
|
type="text"
|
@click="closeDirectOutDialog"
|
class="close-button">
|
×
|
</el-button>
|
</div>
|
<div class="custom-dialog-body">
|
<el-form
|
:model="directOutForm"
|
:rules="directOutFormRules"
|
ref="directOutFormRef"
|
label-width="100px">
|
<el-form-item label="订单编号">
|
<el-input v-model="directOutForm.orderNo" disabled></el-input>
|
</el-form-item>
|
<el-form-item label="托盘编号" prop="palletCode">
|
<el-input
|
v-model="directOutForm.palletCode"
|
placeholder="扫描托盘码"
|
@keyup.enter.native="onDirectOutPalletScan"
|
@change="onDirectOutPalletScan"
|
clearable>
|
</el-input>
|
</el-form-item>
|
</el-form>
|
</div>
|
<div class="custom-dialog-footer">
|
<el-button @click="closeDirectOutDialog">取消</el-button>
|
<el-button type="primary" @click="handleDirectOutConfirm" :loading="directOutLoading">确认出库</el-button>
|
</div>
|
</div>
|
</div>
|
</div>
|
</div>
|
<print-view ref="childs" @parentcall="parentcall"></print-view>
|
</template>
|
|
<script>
|
import http from '@/api/http.js'
|
import { ref, defineComponent } from "vue";
|
import { ElMessage } from 'element-plus'
|
import { useRoute } from 'vue-router'
|
import printView from "@/extension/outbound/extend/printView.vue"
|
|
export default defineComponent({
|
name: 'PickingConfirm',
|
components: {printView},
|
props: {
|
orderNo: {
|
type: String,
|
required: true
|
}
|
},
|
emits: ['confirm', 'close'],
|
data() {
|
// 定义拆包表单验证规则
|
const validateOriginalBarcode = (rule, value, callback) => {
|
if (!value || value.trim() === '') {
|
callback(new Error('请输入原条码'));
|
} else {
|
callback();
|
}
|
};
|
|
const validateSplitQuantity = (rule, value, callback) => {
|
if (value === null || value === undefined || value === '') {
|
callback(new Error('请输入拆包数量'));
|
} else if (value <= 0) {
|
callback(new Error('拆包数量必须大于0'));
|
} else if (this.splitForm.maxQuantity && value > this.splitForm.maxQuantity) {
|
callback(new Error('拆包数量不能大于剩余数量'));
|
} else {
|
callback();
|
}
|
};
|
|
// 定义撤销拆包表单验证规则
|
const validateRevertOriginalBarcode = (rule, value, callback) => {
|
if (!value || value.trim() === '') {
|
callback(new Error('请输入原条码'));
|
} else {
|
callback();
|
}
|
};
|
// 定义批量回库表单验证规则
|
const validateBatchReturnPalletCode = (rule, value, callback) => {
|
if (!value || value.trim() === '') {
|
callback(new Error('请输入托盘码'));
|
} else {
|
callback();
|
}
|
};
|
// 定义直接出库表单验证规则
|
const validateDirectOutPalletCode = (rule, value, callback) => {
|
if (!value || value.trim() === '') {
|
callback(new Error('请输入托盘码'));
|
} else {
|
callback();
|
}
|
};
|
return {
|
scanData: {
|
orderNo: '',
|
palletCode: '',
|
barcode: ''
|
},
|
unpickedList: [],
|
pickedList: [],
|
selectedUnpickedRows: [], // 未拣选列表选中的行
|
selectedPickedRows: [], // 已拣选列表选中的行
|
summary: {
|
unpickedCount: 0,
|
unpickedQuantity: 0,
|
pickedCount: 0
|
},
|
palletStatus: '未知',
|
showSplitDialog: false,
|
showRevertSplitDialog: false,
|
showCustomSplitDialog: false, // 自定义拆包弹窗显示状态
|
showBatchReturnDialog: false, // 批量回库弹窗显示状态
|
showReturnDialog: false,
|
splitLoading: false,
|
revertSplitLoading: false,
|
batchReturnLoading: false, // 批量回库加载状态
|
splitForm: {
|
orderNo: '',
|
palletCode: '',
|
originalBarcode: '',
|
materielCode: '',
|
splitQuantity: 0,
|
maxQuantity: 0
|
},
|
// 拆包表单验证规则
|
splitFormRules: {
|
originalBarcode: [
|
{ required: true, validator: validateOriginalBarcode, trigger: 'blur' }
|
],
|
splitQuantity: [
|
{ required: true, validator: validateSplitQuantity, trigger: 'blur' }
|
]
|
},
|
revertSplitForm: {
|
originalBarcode: ''
|
},
|
// 撤销拆包表单验证规则
|
revertSplitFormRules: {
|
originalBarcode: [
|
{ required: true, validator: validateRevertOriginalBarcode, trigger: 'blur' }
|
]
|
},
|
// 批量回库表单
|
batchReturnForm: {
|
orderNo: '',
|
palletCode: '',
|
unpickedCount: 0,
|
unpickedQuantity: 0
|
},
|
// 批量回库表单验证规则
|
batchReturnFormRules: {
|
palletCode: [
|
{ required: true, validator: validateBatchReturnPalletCode, trigger: 'blur' }
|
]
|
},
|
showDirectOutDialog: false, // 直接出库弹窗显示状态
|
directOutLoading: false, // 直接出库加载状态
|
directOutForm: {
|
orderNo: '',
|
palletCode: ''
|
},
|
directOutFormRules: {
|
palletCode: [
|
{ required: true, validator: validateDirectOutPalletCode, trigger: 'blur' }
|
]
|
},
|
returnForm: {
|
orderNo: '',
|
palletCode: '',
|
barcode: '',
|
materielCode: '',
|
returnQuantity: 0
|
},
|
isProcessing: false // 防止重复提交
|
}
|
},
|
mounted() {
|
// 从路由参数获取订单编号
|
if (this.$route.query.orderNo) {
|
this.scanData.orderNo = this.$route.query.orderNo;
|
this.splitForm.orderNo = this.$route.query.orderNo;
|
this.returnForm.orderNo = this.$route.query.orderNo;
|
}
|
// 页面加载后自动聚焦到托盘码输入框
|
this.$nextTick(() => {
|
this.$refs.palletInput.focus();
|
});
|
|
},
|
methods: {
|
goBack(){
|
this.$router.back()
|
},
|
|
openSplitDialog() {
|
console.log('打开自定义拆包弹窗');
|
if (!this.scanData.palletCode) {
|
this.$message.warning('请先扫描托盘码');
|
return;
|
}
|
this.showCustomSplitDialog = true;
|
|
// 重置表单
|
this.resetSplitForm();
|
|
// 设置订单和托盘信息
|
this.splitForm.orderNo = this.scanData.orderNo;
|
this.splitForm.palletCode = this.scanData.palletCode;
|
|
// 清除表单验证
|
this.$nextTick(() => {
|
if (this.$refs.splitFormRef) {
|
this.$refs.splitFormRef.clearValidate();
|
}
|
});
|
},
|
|
// 关闭自定义拆包弹窗
|
closeCustomSplitDialog() {
|
this.showCustomSplitDialog = false;
|
this.resetSplitForm();
|
// 清除表单验证
|
if (this.$refs.splitFormRef) {
|
this.$refs.splitFormRef.clearValidate();
|
}
|
},
|
|
// 打开撤销拆包弹窗
|
openRevertSplitDialog() {
|
console.log('打开撤销拆包弹窗');
|
this.showRevertSplitDialog = true;
|
|
// 重置表单
|
this.resetRevertSplitForm();
|
|
// 清除表单验证
|
this.$nextTick(() => {
|
if (this.$refs.revertSplitFormRef) {
|
this.$refs.revertSplitFormRef.clearValidate();
|
}
|
});
|
},
|
|
// 关闭撤销拆包弹窗
|
closeRevertSplitDialog() {
|
this.showRevertSplitDialog = false;
|
this.resetRevertSplitForm();
|
|
// 清除表单验证
|
if (this.$refs.revertSplitFormRef) {
|
this.$refs.revertSplitFormRef.clearValidate();
|
}
|
},
|
// 打开批量回库弹窗
|
openBatchReturnDialog() {
|
console.log('打开批量回库弹窗');
|
this.showBatchReturnDialog = true;
|
|
// 重置表单
|
this.resetBatchReturnForm();
|
|
// 设置订单信息
|
this.batchReturnForm.orderNo = this.scanData.orderNo;
|
|
// 更新未拣选信息
|
this.batchReturnForm.unpickedCount = this.summary.unpickedCount || 0;
|
this.batchReturnForm.unpickedQuantity = this.summary.unpickedQuantity || 0;
|
|
// 清除表单验证
|
this.$nextTick(() => {
|
if (this.$refs.batchReturnFormRef) {
|
this.$refs.batchReturnFormRef.clearValidate();
|
}
|
});
|
},
|
|
// 关闭批量回库弹窗
|
closeBatchReturnDialog() {
|
this.showBatchReturnDialog = false;
|
this.resetBatchReturnForm();
|
|
// 清除表单验证
|
if (this.$refs.batchReturnFormRef) {
|
this.$refs.batchReturnFormRef.clearValidate();
|
}
|
},
|
|
// 回库托盘码扫码
|
onBatchReturnPalletScan() {
|
if (!this.batchReturnForm.palletCode) return;
|
|
this.batchReturnForm.palletCode = this.batchReturnForm.palletCode.replace(/\n/g, '').trim();
|
|
// 清除验证状态
|
if (this.$refs.batchReturnFormRef) {
|
this.$refs.batchReturnFormRef.clearValidate(['palletCode']);
|
}
|
},
|
|
// 回库确认
|
async handleBatchReturnConfirm() {
|
// 表单验证
|
if (this.$refs.batchReturnFormRef) {
|
this.$refs.batchReturnFormRef.validate((valid) => {
|
if (valid) {
|
this.submitBatchReturn();
|
} else {
|
this.$message.warning('请扫描托盘码');
|
return false;
|
}
|
});
|
} else {
|
// 如果没有表单引用,使用原有的验证
|
if (!this.batchReturnForm.palletCode) {
|
this.$message.warning('请扫描托盘码');
|
return;
|
}
|
|
this.submitBatchReturn();
|
}
|
},
|
|
// 提交回库请求
|
async submitBatchReturn() {
|
this.batchReturnLoading = true;
|
|
try {
|
const res = await this.http.post('/api/OutboundPicking/return-to-stock', {
|
orderNo: this.batchReturnForm.orderNo,
|
palletCode: this.batchReturnForm.palletCode
|
});
|
|
if (res.status) {
|
this.$message.success(res.message);
|
this.showBatchReturnDialog = false;
|
this.loadData();
|
} else {
|
this.$message.error(res.message || '回库失败');
|
}
|
} catch (error) {
|
this.$message.error('回库失败');
|
} finally {
|
this.batchReturnLoading = false;
|
}
|
},
|
// 打开直接出库弹窗
|
openDirectOutDialog() {
|
console.log('打开直接出库弹窗');
|
this.showDirectOutDialog = true;
|
|
// 重置表单
|
this.resetDirectOutForm();
|
|
// 设置订单信息
|
this.directOutForm.orderNo = this.scanData.orderNo;
|
|
// 清除表单验证
|
this.$nextTick(() => {
|
if (this.$refs.directOutFormRef) {
|
this.$refs.directOutFormRef.clearValidate();
|
}
|
});
|
},
|
|
// 关闭直接出库弹窗
|
closeDirectOutDialog() {
|
this.showDirectOutDialog = false;
|
this.resetDirectOutForm();
|
|
// 清除表单验证
|
if (this.$refs.directOutFormRef) {
|
this.$refs.directOutFormRef.clearValidate();
|
}
|
},
|
|
// 直接出库托盘码扫码
|
onDirectOutPalletScan() {
|
if (!this.directOutForm.palletCode) return;
|
|
this.directOutForm.palletCode = this.directOutForm.palletCode.replace(/\n/g, '').trim();
|
|
// 清除验证状态
|
if (this.$refs.directOutFormRef) {
|
this.$refs.directOutFormRef.clearValidate(['palletCode']);
|
}
|
},
|
|
// 直接出库确认
|
async handleDirectOutConfirm() {
|
// 表单验证
|
if (this.$refs.directOutFormRef) {
|
this.$refs.directOutFormRef.validate((valid) => {
|
if (valid) {
|
this.submitDirectOut();
|
} else {
|
this.$message.warning('请扫描托盘码');
|
return false;
|
}
|
});
|
} else {
|
// 如果没有表单引用,使用原有的验证
|
if (!this.directOutForm.palletCode) {
|
this.$message.warning('请扫描托盘码');
|
return;
|
}
|
|
this.submitDirectOut();
|
}
|
},
|
|
// 提交直接出库请求
|
async submitDirectOut() {
|
this.directOutLoading = true;
|
|
try {
|
const res = await this.http.post('/api/OutboundPicking/direct-outbound', {
|
orderNo: this.directOutForm.orderNo,
|
palletCode: this.directOutForm.palletCode
|
});
|
debugger;
|
if (res.status) {
|
this.$message.success('直接出库成功');
|
this.showDirectOutDialog = false;
|
this.loadData();
|
} else {
|
this.$message.error(res.message || '直接出库失败');
|
}
|
} catch (error) {
|
this.$message.error('直接出库失败');
|
} finally {
|
this.directOutLoading = false;
|
}
|
},
|
|
// 重置直接出库表单
|
resetDirectOutForm() {
|
this.directOutForm.palletCode = '';
|
},
|
|
// 修改原有的直接出库按钮点击事件
|
handleDirectOutbound() {
|
this.openDirectOutDialog();
|
},
|
async loadData() {
|
if (!this.scanData.orderNo || !this.scanData.palletCode) {
|
return;
|
}
|
|
try {
|
// 加载未拣选列表
|
const unpickedRes = await this.http.post('/api/OutboundPicking/unpicked-list', this.scanData);
|
this.unpickedList = unpickedRes.data || [];
|
|
// 加载已拣选列表
|
const pickedRes = await this.http.post('/api/OutboundPicking/picked-list', this.scanData);
|
this.pickedList = pickedRes.data || [];
|
|
// 加载汇总信息
|
const summaryRes = await this.http.post('/api/OutboundPicking/picking-summary',this.scanData);
|
this.summary = summaryRes.data || {};
|
|
// 更新托盘状态
|
this.updatePalletStatus();
|
|
} catch (error) {
|
this.$message.error('加载数据失败');
|
}
|
},
|
|
updatePalletStatus() {
|
if (this.unpickedList.length === 0 && this.pickedList.length > 0) {
|
this.palletStatus = '已全部拣选';
|
} else if (this.unpickedList.length > 0 && this.pickedList.length === 0) {
|
this.palletStatus = '待拣选';
|
} else if (this.unpickedList.length > 0 && this.pickedList.length > 0) {
|
this.palletStatus = '部分拣选';
|
} else {
|
this.palletStatus = '无数据';
|
}
|
},
|
// 已拣选列表选择变化
|
handlePickedSelectionChange(selection) {
|
this.selectedPickedRows = selection;
|
},
|
// 批量取消选中的已拣选项
|
async batchCancelSelected() {
|
if (this.selectedPickedRows.length === 0) {
|
this.$message.warning('请先选择要取消的项');
|
return;
|
}
|
|
this.$confirm(`确定要取消选中的 ${this.selectedPickedRows.length} 项吗?`, '提示', {
|
confirmButtonText: '确定',
|
cancelButtonText: '取消',
|
type: 'warning'
|
}).then(async () => {
|
try {
|
let successCount = 0;
|
let errorCount = 0;
|
|
for (const row of this.selectedPickedRows) {
|
try {
|
const res = await this.http.post('/api/OutboundPicking/CancelPicking', {
|
orderNo: this.scanData.orderNo,
|
palletCode: this.scanData.palletCode,
|
barcode: row.currentBarcode
|
});
|
|
if (res.status) {
|
successCount++;
|
} else {
|
errorCount++;
|
console.error(`取消拣选失败: ${row.Barcode}`, res.message);
|
}
|
} catch (error) {
|
errorCount++;
|
console.error(`取消拣选失败: ${row.Barcode}`, error);
|
}
|
}
|
|
if (errorCount === 0) {
|
this.$message.success(`成功取消 ${successCount} 项`);
|
} else {
|
this.$message.warning(`成功取消 ${successCount} 项,失败 ${errorCount} 项`);
|
}
|
|
this.loadData();
|
this.selectedPickedRows = [];
|
} catch (error) {
|
this.$message.error('批量取消操作失败');
|
}
|
}).catch(() => {
|
this.$message.info('已取消批量操作');
|
});
|
},
|
// 托盘码扫码
|
onPalletScan() {
|
// 去除回车符和前后空格
|
this.scanData.palletCode = this.scanData.palletCode.replace(/\n/g, '').trim();
|
if (!this.scanData.palletCode) return;
|
|
this.splitForm.palletCode = this.scanData.palletCode;
|
this.returnForm.palletCode = this.scanData.palletCode;
|
|
// 加载数据
|
this.loadData();
|
|
// 自动跳转到物料条码输入框
|
this.$nextTick(() => {
|
this.$refs.barcodeInput.focus();
|
});
|
},
|
|
onBarcodeScan() {
|
// 去除回车符和前后空格
|
this.scanData.barcode = this.scanData.barcode.replace(/\n/g, '').trim();
|
if (!this.scanData.barcode) return;
|
|
// 自动确认拣选
|
this.confirmPicking();
|
},
|
|
async confirmPicking() {
|
if (this.isProcessing) return;
|
|
if (!this.scanData.orderNo || !this.scanData.palletCode || !this.scanData.barcode) {
|
this.$message.warning('请先扫描托盘码和物料条码');
|
this.focusBarcodeInput();
|
return;
|
}
|
|
this.isProcessing = true;
|
|
try {
|
const res = await this.http.post('/api/OutboundPicking/confirm-picking', this.scanData);
|
if (res.status) {
|
this.$message.success('拣选确认成功');
|
this.scanData.barcode = ''; // 清空物料条码
|
this.loadData();
|
console.log(res.data.splitResults)
|
if(res.data && res.data.splitResults.length>0){
|
// 调用子组件打印方法
|
this.$refs.childs.open(res.data.splitResults);
|
//this.$refs.childs.printSplitLabel(res.data.splitResults);
|
}
|
// 成功后继续聚焦到物料条码输入框,准备下一个扫码
|
this.$nextTick(() => {
|
this.$refs.barcodeInput.focus();
|
});
|
} else {
|
// 显示后端返回的错误信息
|
this.$message.error(res.message || '拣选确认失败');
|
// 失败时聚焦并选中物料条码输入框内容
|
this.focusBarcodeInput(true);
|
}
|
} catch (error) {
|
this.$message.error('拣选确认失败: ' + (error.message || '网络错误'));
|
// 失败时聚焦并选中物料条码输入框内容
|
this.focusBarcodeInput(true);
|
} finally {
|
this.isProcessing = false;
|
}
|
},
|
|
// 聚焦到物料条码输入框
|
focusBarcodeInput(selectText = false) {
|
this.$nextTick(() => {
|
const input = this.$refs.barcodeInput;
|
if (input && input.$el && input.$el.querySelector('input')) {
|
const inputEl = input.$el.querySelector('input');
|
inputEl.focus();
|
if (selectText) {
|
inputEl.select();
|
}
|
}
|
});
|
},
|
|
async cancelPicking(row) {
|
try {
|
const res = await this.http.post('/api/OutboundPicking/CancelPicking', {
|
orderNo: this.scanData.orderNo,
|
palletCode: this.scanData.palletCode,
|
barcode: row.Barcode
|
});
|
|
if (res.status) {
|
this.$message.success('取消拣选成功');
|
this.loadData();
|
} else {
|
this.$message.error(res.message || '取消拣选失败');
|
}
|
} catch (error) {
|
this.$message.error('取消拣选失败');
|
}
|
},
|
|
/* // 回库操作 - 回库整个托盘未拣选的货物
|
async handleBatchReturn() {
|
if (!this.scanData.orderNo || !this.scanData.palletCode) {
|
this.$message.warning('请先扫描托盘码');
|
return;
|
}
|
|
if (this.unpickedList.length === 0) {
|
this.$message.warning('该托盘没有可回库的货物');
|
return;
|
}
|
|
this.$confirm(`确定要回库整个托盘的未拣选货物吗?共 ${this.unpickedList.length} 条记录`, '提示', {
|
confirmButtonText: '确定',
|
cancelButtonText: '取消',
|
type: 'warning'
|
}).then(async () => {
|
try {
|
const res = await this.http.post('/api/OutboundPicking/batch-return-to-stock', {
|
orderNo: this.scanData.orderNo,
|
palletCode: this.scanData.palletCode
|
});
|
|
if (res.success) {
|
this.$message.success('批量回库成功');
|
this.loadData();
|
} else {
|
this.$message.error(res.message || '批量回库失败');
|
}
|
} catch (error) {
|
this.$message.error('批量回库失败');
|
}
|
}).catch(() => {
|
this.$message.info('已取消批量回库');
|
});
|
}, */
|
|
/* // 直接出库操作
|
async handleDirectOutbound() {
|
if (!this.scanData.orderNo || !this.scanData.palletCode) {
|
this.$message.warning('请先扫描托盘码');
|
return;
|
}
|
|
this.$confirm('确定要直接出库整个托盘吗?', '提示', {
|
confirmButtonText: '确定',
|
cancelButtonText: '取消',
|
type: 'warning'
|
}).then(async () => {
|
try {
|
const res = await this.http.post('/api/OutboundPicking/direct-outbound', {
|
orderNo: this.scanData.orderNo,
|
palletCode: this.scanData.palletCode
|
});
|
|
if (res.success) {
|
this.$message.success('直接出库成功');
|
this.loadData();
|
} else {
|
this.$message.error(res.message || '直接出库失败');
|
}
|
} catch (error) {
|
this.$message.error('直接出库失败');
|
}
|
}).catch(() => {
|
this.$message.info('已取消直接出库');
|
});
|
}, */
|
// 确认回库(通过弹窗)
|
async handleReturnConfirm() {
|
if (!this.returnForm.barcode) {
|
this.$message.warning('请扫描回库条码');
|
return;
|
}
|
|
try {
|
const res = await this.http.post('/api/OutboundPicking/return-to-stock', {
|
orderNo: this.returnForm.orderNo,
|
palletCode: this.returnForm.palletCode,
|
barcode: this.returnForm.barcode
|
});
|
|
if (res.status) {
|
this.$message.success('回库成功');
|
this.showReturnDialog = false;
|
this.resetReturnForm();
|
this.loadData();
|
} else {
|
this.$message.error(res.message || '回库失败');
|
}
|
} catch (error) {
|
this.$message.error('回库失败');
|
}
|
},
|
|
// 拆包扫码
|
async onSplitBarcodeScan() {
|
if (!this.splitForm.originalBarcode) return;
|
|
// 去除回车符和前后空格
|
this.splitForm.originalBarcode = this.splitForm.originalBarcode.replace(/\n/g, '').trim();
|
|
try {
|
const res = await this.http.post('/api/OutboundPicking/split-package-info', {
|
|
orderNo: this.splitForm.orderNo,
|
palletCode: this.splitForm.palletCode,
|
barcode: this.splitForm.originalBarcode
|
|
});
|
|
if (res.status) {
|
this.splitForm.materielCode = res.data.materielCode;
|
this.splitForm.maxQuantity = res.data.remainQuantity;
|
this.splitForm.splitQuantity = Math.min(1, this.splitForm.maxQuantity);
|
// 清除验证状态
|
if (this.$refs.splitFormRef) {
|
this.$refs.splitFormRef.clearValidate(['originalBarcode']);
|
}
|
} else {
|
this.$message.error(res.message || '获取拆包信息失败');
|
// 验证失败,设置错误状态
|
if (this.$refs.splitFormRef) {
|
this.$refs.splitFormRef.validateField('originalBarcode');
|
}
|
}
|
} catch (error) {
|
this.$message.error('获取拆包信息失败');
|
// 验证失败,设置错误状态
|
if (this.$refs.splitFormRef) {
|
this.$refs.splitFormRef.validateField('originalBarcode');
|
}
|
}
|
},
|
|
async handleSplitPackage() {
|
// 表单验证
|
if (this.$refs.splitFormRef) {
|
this.$refs.splitFormRef.validate((valid) => {
|
if (valid) {
|
this.submitSplitPackage();
|
} else {
|
this.$message.warning('请填写完整的拆包信息');
|
return false;
|
}
|
});
|
} else {
|
// 如果没有表单引用,使用原有的验证
|
if (!this.splitForm.originalBarcode || this.splitForm.splitQuantity <= 0) {
|
this.$message.warning('请填写完整的拆包信息');
|
return;
|
}
|
|
if (this.splitForm.splitQuantity > this.splitForm.maxQuantity) {
|
this.$message.warning('拆包数量不能大于剩余数量');
|
return;
|
}
|
|
this.submitSplitPackage();
|
}
|
|
|
},
|
// 提交拆包请求
|
async submitSplitPackage() {
|
this.splitLoading = true;
|
try {
|
const res = await this.http.post('/api/OutboundPicking/split-package', this.splitForm);
|
if (res.status) {
|
this.$message.success('拆包成功');
|
this.showSplitDialog = false;
|
this.splitLoading = false;
|
this.resetSplitForm();
|
this.loadData();
|
} else {
|
this.splitLoading = false;
|
this.$message.error(res.message || '拆包失败');
|
}
|
} catch (error) {
|
this.splitLoading = false;
|
this.$message.error('拆包失败');
|
}
|
},
|
// 撤销拆包扫码
|
onRevertSplitBarcodeScan() {
|
if (!this.revertSplitForm.originalBarcode) return;
|
|
this.revertSplitForm.originalBarcode = this.revertSplitForm.originalBarcode.replace(/\n/g, '').trim();
|
|
// 清除验证状态
|
if (this.$refs.revertSplitFormRef) {
|
this.$refs.revertSplitFormRef.clearValidate(['originalBarcode']);
|
}
|
},
|
async handleRevertSplit() {
|
// 表单验证
|
if (this.$refs.revertSplitFormRef) {
|
this.$refs.revertSplitFormRef.validate((valid) => {
|
if (valid) {
|
this.submitRevertSplit();
|
} else {
|
this.$message.warning('请输入原条码');
|
return false;
|
}
|
});
|
} else {
|
// 如果没有表单引用,使用原有的验证
|
if (!this.revertSplitForm.originalBarcode) {
|
this.$message.warning('请输入原条码');
|
return;
|
}
|
|
this.submitRevertSplit();
|
}
|
},
|
// 提交撤销拆包请求
|
async submitRevertSplit() {
|
this.revertSplitLoading = true;
|
|
try {
|
const res = await this.http.post('/api/OutboundPicking/revert-split-package', {
|
originalBarcode: this.revertSplitForm.originalBarcode
|
});
|
|
if (res.status) {
|
this.$message.success('撤销拆包成功');
|
this.showRevertSplitDialog = false;
|
this.revertSplitLoading = false;
|
this.revertSplitForm.originalBarcode = '';
|
this.loadData();
|
} else {
|
this.revertSplitLoading = false;
|
this.$message.error(res.message || '撤销拆包失败');
|
}
|
} catch (error) {
|
this.revertSplitLoading = false;
|
this.$message.error('撤销拆包失败');
|
}
|
},
|
resetSplitForm() {
|
this.splitForm.originalBarcode = '';
|
this.splitForm.materielCode = '';
|
this.splitForm.splitQuantity = 0;
|
this.splitForm.maxQuantity = 0;
|
},
|
// 重置批量回库表单
|
resetBatchReturnForm() {
|
this.batchReturnForm.palletCode = '';
|
this.batchReturnForm.unpickedCount = 0;
|
this.batchReturnForm.unpickedQuantity = 0;
|
},
|
resetReturnForm() {
|
this.returnForm.barcode = '';
|
this.returnForm.materielCode = '';
|
this.returnForm.returnQuantity = 0;
|
}
|
}
|
})
|
</script>
|
|
<style scoped>
|
.picking-container {
|
padding: 20px;
|
position: relative; /* 为弹窗定位提供上下文 */
|
}
|
.scanner-form {
|
display: flex;
|
gap: 10px;
|
align-items: center;
|
flex-wrap: wrap;
|
}
|
.scanner-form .el-input {
|
width: 200px;
|
}
|
.summary-info {
|
display: flex;
|
gap: 20px;
|
flex-wrap: wrap;
|
}
|
|
/* 表格操作区域样式 */
|
.table-actions {
|
display: flex;
|
justify-content: space-between;
|
align-items: center;
|
margin-bottom: 10px;
|
padding: 0 10px;
|
}
|
|
.selection-count {
|
font-size: 12px;
|
color: #909399;
|
}
|
|
/* 表格样式调整 */
|
.content-area .el-table {
|
margin-top: 0;
|
}
|
|
/* 确保表格高度适应 */
|
.content-area .el-card__body {
|
padding: 15px;
|
}
|
|
|
/* 自定义弹窗样式 */
|
.custom-dialog-overlay {
|
position: fixed;
|
top: 0;
|
left: 0;
|
right: 0;
|
bottom: 0;
|
background-color: rgba(0, 0, 0, 0.5);
|
display: flex;
|
align-items: center;
|
justify-content: center;
|
z-index: 9999;
|
}
|
|
.custom-dialog-wrapper {
|
position: relative;
|
z-index: 10000;
|
}
|
|
.custom-dialog {
|
background: white;
|
border-radius: 4px;
|
width: 500px;
|
max-width: 90vw;
|
max-height: 90vh;
|
box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
|
overflow: auto;
|
}
|
|
.custom-dialog-header {
|
display: flex;
|
justify-content: space-between;
|
align-items: center;
|
padding: 20px 20px 10px;
|
border-bottom: 1px solid #ebeef5;
|
}
|
|
.custom-dialog-header h3 {
|
margin: 0;
|
color: #303133;
|
}
|
|
/* 关闭按钮样式 */
|
.close-button {
|
font-size: 18px;
|
color: #909399;
|
padding: 0;
|
width: 24px;
|
height: 24px;
|
display: flex;
|
align-items: center;
|
justify-content: center;
|
}
|
|
.close-button:hover {
|
color: #409EFF;
|
background-color: transparent;
|
}
|
|
.custom-dialog-body {
|
padding: 20px;
|
}
|
|
.custom-dialog-footer {
|
padding: 10px 20px 20px;
|
text-align: right;
|
border-top: 1px solid #ebeef5;
|
}
|
|
.custom-dialog-footer .el-button {
|
margin-left: 10px;
|
}
|
|
/* 确保弹窗在移动设备上也能正常显示 */
|
@media (max-width: 768px) {
|
.custom-dialog {
|
width: 95vw;
|
margin: 10px;
|
}
|
}
|
</style>
|