<template>
|
<!-- 出库操作弹窗 -->
|
<vol-box
|
v-model="visible"
|
:title="'出库单处理 - 单据号:' + (selectedDocument?.transNo || '')"
|
:height="580"
|
:width="900"
|
:padding="20"
|
:modal="true"
|
@model-close="handleClose"
|
>
|
<template #content>
|
<!-- 出库单基本信息 -->
|
<div class="mb-6 bg-neutral-50 p-4 rounded-lg">
|
<div class="grid grid-cols-1 md:grid-cols-3 gap-4">
|
<div>
|
<label class="text-sm text-neutral-500 block mb-1">出库单编号</label>
|
<el-input
|
v-model="selectedDocument.transNo"
|
readonly
|
border="none"
|
class="font-medium text-primary bg-transparent"
|
size="small"
|
></el-input>
|
</div>
|
<div>
|
<label class="text-sm text-neutral-500 block mb-1">出库日期</label>
|
<el-input
|
v-model="selectedDocument.createDate"
|
readonly
|
border="none"
|
class="font-medium bg-transparent"
|
size="small"
|
></el-input>
|
</div>
|
</div>
|
</div>
|
|
<!-- 可用明细列表(不可编辑,点击选择) -->
|
<div class="mb-8">
|
<div class="flex items-center justify-between mb-4">
|
<h4 class="font-semibold text-neutral-700">出库单明细(点击选择)</h4>
|
<el-tooltip effect="dark" content="点击明细行添加到下方编辑区">
|
<span class="text-sm text-neutral-500 flex items-center">
|
<i class="fa fa-info-circle mr-1"></i> 操作提示
|
</span>
|
</el-tooltip>
|
</div>
|
|
<el-table
|
:data="availableItems"
|
border
|
size="small"
|
:height="180"
|
@row-click="handleItemSelect"
|
ref="availableTable"
|
highlight-current-row
|
>
|
<el-table-column
|
prop="transNo"
|
label="单据编号"
|
width="120"
|
></el-table-column>
|
<el-table-column
|
prop="materialCode"
|
label="物料编号"
|
min-width="120"
|
></el-table-column>
|
<el-table-column
|
prop="materialName"
|
label="物料名称"
|
width="150"
|
></el-table-column>
|
<el-table-column
|
prop="qtyTrans"
|
label="出库数量"
|
width="100"
|
></el-table-column>
|
</el-table>
|
</div>
|
|
<!-- 已选明细列表(可编辑数量) -->
|
<div>
|
<div class="flex items-center justify-between mb-4">
|
<h4 class="font-semibold text-neutral-700">已选择出库明细</h4>
|
<el-button
|
type="danger"
|
size="small"
|
@click="clearSelectedItems"
|
:disabled="selectedItems.length === 0"
|
>
|
<i class="fa fa-trash-o mr-1"></i>清空列表
|
</el-button>
|
</div>
|
|
<el-table
|
:data="selectedItems"
|
border
|
size="small"
|
:height="180"
|
ref="selectedTable"
|
>
|
<el-table-column
|
prop="transNo"
|
label="单据编号"
|
width="120"
|
></el-table-column>
|
<el-table-column
|
prop="materialCode"
|
label="物料编号"
|
min-width="200"
|
></el-table-column>
|
<el-table-column
|
prop="materialName"
|
label="物料名称"
|
width="150"
|
></el-table-column>
|
<el-table-column
|
prop="availableQty"
|
label="出库数量"
|
width="180"
|
>
|
<template #default="scope">
|
<div class="flex items-center">
|
<el-button
|
type="text"
|
size="mini"
|
icon="el-icon-minus"
|
@click.stop="adjustQuantity(scope.row, -1)"
|
:disabled="scope.row.quantity <= 1"
|
class="w-8 h-8 p-0"
|
></el-button>
|
<el-input-number
|
v-model="scope.row.quantity"
|
:min="1"
|
:max="scope.row.availableQty"
|
:precision="0"
|
size="mini"
|
class="w-16"
|
@change="validateQuantity(scope.row)"
|
></el-input-number>
|
<el-button
|
type="text"
|
size="mini"
|
icon="el-icon-plus"
|
@click.stop="adjustQuantity(scope.row, 1)"
|
:disabled="scope.row.quantity >= scope.row.availableQty"
|
class="w-8 h-8 p-0"
|
></el-button>
|
</div>
|
</template>
|
</el-table-column>
|
<el-table-column
|
label="操作"
|
width="80"
|
align="center"
|
>
|
<template #default="scope">
|
<el-button
|
type="text"
|
size="small"
|
icon="el-icon-delete"
|
class="text-danger"
|
@click.stop="removeItem(scope.row)"
|
></el-button>
|
</template>
|
</el-table-column>
|
</el-table>
|
|
|
</div>
|
</template>
|
|
<template #footer>
|
<div class="flex justify-end gap-3">
|
<el-button
|
type="default"
|
size="small"
|
@click="handleClose"
|
>
|
取消
|
</el-button>
|
<el-button
|
type="primary"
|
size="small"
|
@click="confirmOutbound"
|
:disabled="selectedItems.length === 0"
|
>
|
<i class="fa fa-sign-out mr-1"></i>确认出库
|
</el-button>
|
</div>
|
</template>
|
</vol-box>
|
</template>
|
|
<script>
|
import VolBox from '@/components/basic/VolBox.vue';
|
import { ElMessage, ElMessageBox, ElLoading } from 'element-plus';
|
import http from '@/api/http.js';
|
|
export default {
|
name: 'OutboundDialog',
|
components: { VolBox },
|
props: {
|
// 控制弹窗显示/隐藏
|
visible: {
|
type: Boolean,
|
default: false
|
},
|
// 选中的出库单数据
|
selectedDocument: {
|
type: Object,
|
default: () => ({
|
transNo: '',
|
createDate: ''
|
})
|
}
|
},
|
data() {
|
return {
|
// 可用明细数据(从接口获取)
|
availableItems: [],
|
// 已选择的明细
|
selectedItems: []
|
};
|
},
|
watch: {
|
'selectedDocument.transNo': { // 优化监听
|
handler(newVal, oldVal) {
|
if (newVal && newVal !== oldVal) {
|
this.selectedItems = [];
|
this.loadDocumentItems(newVal);
|
}
|
}
|
}
|
},
|
methods: {
|
// 关闭弹窗
|
handleClose() {
|
this.$emit('update:visible', false);
|
},
|
|
// 选择明细项
|
handleItemSelect(item) {
|
// 检查是否已选择
|
const isExist = this.selectedItems.some(i => i.id === item.id);
|
if (isExist) {
|
ElMessage.warning('该商品已在出库列表中');
|
return;
|
}
|
|
// 添加到已选列表(默认数量1)
|
this.selectedItems.push({
|
...item,
|
quantity: 1,
|
});
|
},
|
|
// 调整数量
|
adjustQuantity(item, delta) {
|
item.quantity += delta;
|
},
|
|
// 验证数量范围
|
validateQuantity(item) {
|
if (isNaN(item.quantity) || item.quantity < 1) {
|
item.quantity = 1;
|
} else if (item.quantity > item.availableQty) {
|
item.quantity = item.availableQty;
|
ElMessage.warning(`最大可出库数量为${item.quantity}`);
|
}
|
},
|
|
// 移除单个已选项目
|
removeItem(item) {
|
this.selectedItems = this.selectedItems.filter(i => i.id !== item.id);
|
},
|
|
// 清空已选列表
|
clearSelectedItems() {
|
ElMessageBox.confirm(
|
'确定要清空所有已选择的出库明细吗?',
|
'确认操作',
|
{
|
confirmButtonText: '确定',
|
cancelButtonText: '取消',
|
type: 'warning'
|
}
|
).then(() => {
|
this.selectedItems = [];
|
});
|
},
|
|
// 确认出库
|
confirmOutbound() {
|
// 收集出库数据
|
const outboundData = {
|
transNo: this.selectedDocument.transNo,
|
items: this.selectedItems.map(item => ({
|
transNo: item.transNo,
|
materialCode: item.materialCode,
|
materialName: item.materialName,
|
quantity: item.quantity,
|
}))
|
};
|
|
// 显示加载状态
|
const loading = ElLoading.service({
|
lock: true,
|
text: '正在执行出库操作...',
|
background: 'rgba(0, 0, 0, 0.7)'
|
});
|
|
// 调用出库接口
|
http.post('/api/outbound/execute', outboundData)
|
.then(response => {
|
if (response.success) {
|
ElMessage.success('出库操作执行成功');
|
this.handleClose();
|
// 通知父组件刷新列表
|
this.$emit('outbound-success', this.selectedDocument.documentNo);
|
} else {
|
ElMessage.error(response.message || '出库操作失败');
|
}
|
})
|
.catch(error => {
|
console.error('出库接口异常:', error);
|
ElMessage.error('网络异常,出库操作失败');
|
})
|
.finally(() => {
|
loading.close();
|
});
|
},
|
|
// 加载单据对应明细(实际项目中实现)
|
loadDocumentItems(documentNo) {
|
const loading = ElLoading.service({ text: '加载明细数据中...' });
|
http.post(`/api/DocumentDetail/Details`, { transNo :this.selectedDocument.transNo})
|
.then(response => {
|
const nestedBackendData = response.data || [];
|
|
const backendData = Array.isArray(nestedBackendData[0])
|
? nestedBackendData[0]
|
: nestedBackendData;
|
|
const newDataList = backendData.map(item => ({
|
transNo: item.transNo,
|
materialCode: item.materialCode,
|
materialName: item.materialName,
|
qtyTrans: item.qtyTrans,
|
// 关键:确保availableQty是正数(默认1,避免0或负数)
|
availableQty: Math.max(Number(item.qtyTrans) || 1, 1)
|
}));
|
|
this.availableItems = [...this.availableItems,...newDataList];
|
})
|
.catch(error => {
|
console.error('加载明细失败:', error);
|
ElMessage.error('加载明细数据失败');
|
})
|
.finally(() => {
|
loading.close();
|
});
|
}
|
}
|
};
|
</script>
|
|
<style scoped>
|
::v-deep .el-input__inner {
|
background-color: transparent !important;
|
}
|
|
::v-deep .el-table__row:hover {
|
background-color: #e6f7ff !important;
|
}
|
|
::v-deep .el-table__current-row {
|
background-color: #e6f7ff !important;
|
}
|
</style>
|