<template>
|
<el-dialog
|
:model-value="dialogGenerateVisible"
|
@update:model-value="$emit('update:dialogGenerateVisible', $event)"
|
title="一键生成退货单"
|
width="1000px"
|
:close-on-click-modal="false"
|
>
|
<div class="generate-container">
|
<!-- 选择采购订单 -->
|
<el-card class="select-card" shadow="never">
|
<template #header>
|
<div class="card-header">
|
<span>选择采购订单</span>
|
</div>
|
</template>
|
|
<el-form :inline="true" :model="searchForm" class="search-form">
|
<el-form-item label="供应商">
|
<el-select
|
v-model="searchForm.supplierId"
|
placeholder="请选择供应商"
|
clearable
|
style="width: 200px"
|
@change="handleSupplierChange"
|
>
|
<el-option
|
:label="item.label"
|
v-for="item in supplierList"
|
:key="item.value"
|
:value="item.value"
|
/>
|
</el-select>
|
</el-form-item>
|
<el-form-item label="订单状态">
|
<el-select
|
v-model="searchForm.orderStatus"
|
placeholder="请选择订单状态"
|
clearable
|
style="width: 150px"
|
>
|
<el-option
|
:label="item.label"
|
v-for="item in orderStatusList"
|
:key="item.value"
|
:value="item.value"
|
/>
|
</el-select>
|
</el-form-item>
|
<el-form-item>
|
<el-button type="primary" @click="searchOrders">查询</el-button>
|
<el-button @click="resetSearch">重置</el-button>
|
</el-form-item>
|
</el-form>
|
|
<el-table
|
:data="orderList"
|
@selection-change="handleOrderSelectionChange"
|
border
|
style="width: 100%"
|
max-height="300"
|
>
|
<el-table-column type="selection" width="55" />
|
<el-table-column label="订单号" prop="orderNo" width="180" />
|
<el-table-column label="供应商" prop="supplierName" width="150" />
|
<el-table-column label="订单日期" prop="orderDate" width="120" />
|
<el-table-column label="商品名称" prop="coalName" width="150" />
|
<el-table-column label="订单数量" prop="orderQuantity" width="100">
|
<template #default="scope">
|
{{ scope.row.orderQuantity }} 吨
|
</template>
|
</el-table-column>
|
<el-table-column label="已收货数量" prop="receivedQuantity" width="100">
|
<template #default="scope">
|
{{ scope.row.receivedQuantity }} 吨
|
</template>
|
</el-table-column>
|
<el-table-column label="状态" prop="status" width="100">
|
<template #default="scope">
|
<el-tag :type="getOrderStatusType(scope.row.status)">
|
{{ getOrderStatusText(scope.row.status) }}
|
</el-tag>
|
</template>
|
</el-table-column>
|
</el-table>
|
</el-card>
|
|
<!-- 退货信息配置 -->
|
<el-card class="config-card" shadow="never">
|
<template #header>
|
<div class="card-header">
|
<span>退货信息配置</span>
|
</div>
|
</template>
|
|
<el-form :model="returnConfig" label-width="120px" class="config-form">
|
<el-row :gutter="20">
|
<el-col :span="12">
|
<el-form-item label="退货原因" prop="returnReason">
|
<el-select
|
v-model="returnConfig.returnReason"
|
placeholder="请选择退货原因"
|
style="width: 100%"
|
filterable
|
allow-create
|
>
|
<el-option
|
:label="item.label"
|
v-for="item in returnReasonList"
|
:key="item.value"
|
:value="item.value"
|
/>
|
</el-select>
|
</el-form-item>
|
</el-col>
|
<el-col :span="12">
|
<el-form-item label="操作员" prop="operatorId">
|
<el-select
|
v-model="returnConfig.operatorId"
|
placeholder="请选择操作员"
|
style="width: 100%"
|
filterable
|
>
|
<el-option
|
:label="item.label"
|
v-for="item in operatorList"
|
:key="item.value"
|
:value="item.value"
|
/>
|
</el-select>
|
</el-form-item>
|
</el-col>
|
</el-row>
|
|
<el-form-item label="备注" prop="remark">
|
<el-input
|
v-model="returnConfig.remark"
|
type="textarea"
|
:rows="3"
|
placeholder="请输入备注信息"
|
/>
|
</el-form-item>
|
</el-form>
|
</el-card>
|
|
<!-- 预览退货单 -->
|
<el-card class="preview-card" shadow="never">
|
<template #header>
|
<div class="card-header">
|
<span>预览退货单</span>
|
</div>
|
</template>
|
|
<div v-if="selectedOrders.length === 0" class="no-selection">
|
<el-empty description="请先选择要退货的采购订单" />
|
</div>
|
|
<div v-else class="preview-content">
|
<el-table :data="previewReturnItems" border style="width: 100%">
|
<el-table-column label="订单号" prop="orderNo" width="150" />
|
<el-table-column label="商品名称" prop="coalName" width="150" />
|
<el-table-column label="退货数量" width="120">
|
<template #default="scope">
|
<el-input
|
v-model.number="scope.row.returnQuantity"
|
placeholder="退货数量"
|
type="number"
|
@input="updateReturnQuantity(scope.$index)"
|
>
|
<template v-slot:suffix>
|
<span>吨</span>
|
</template>
|
</el-input>
|
</template>
|
</el-table-column>
|
<el-table-column label="单价" prop="unitPrice" width="120">
|
<template #default="scope">
|
{{ scope.row.unitPrice }} 元/吨
|
</template>
|
</el-table-column>
|
<el-table-column label="小计" width="120">
|
<template #default="scope">
|
{{ (scope.row.returnQuantity * scope.row.unitPrice).toFixed(2) }} 元
|
</template>
|
</el-table-column>
|
</el-table>
|
|
<div class="preview-summary">
|
<span class="summary-item">
|
总数量:<strong>{{ getTotalReturnQuantity() }} 吨</strong>
|
</span>
|
<span class="summary-item">
|
总金额:<strong>{{ getTotalReturnAmount() }} 元</strong>
|
</span>
|
</div>
|
</div>
|
</el-card>
|
</div>
|
|
<template #footer>
|
<div class="dialog-footer">
|
<el-button @click="handleClose">取消</el-button>
|
<el-button
|
type="primary"
|
@click="generateReturnOrder"
|
:loading="generateLoading"
|
:disabled="selectedOrders.length === 0"
|
>
|
生成退货单
|
</el-button>
|
</div>
|
</template>
|
</el-dialog>
|
</template>
|
|
<script setup>
|
import { ref, reactive, computed, watch } from "vue";
|
import { ElMessage } from "element-plus";
|
|
// Props
|
const props = defineProps({
|
dialogGenerateVisible: {
|
type: Boolean,
|
default: false
|
}
|
});
|
|
// Emits
|
const emit = defineEmits(['update:dialogGenerateVisible', 'success']);
|
|
// 响应式数据
|
const searchForm = reactive({
|
supplierId: "",
|
orderStatus: ""
|
});
|
|
const returnConfig = reactive({
|
returnReason: "",
|
operatorId: "",
|
remark: ""
|
});
|
|
const orderList = ref([]);
|
const selectedOrders = ref([]);
|
const generateLoading = ref(false);
|
|
// 供应商列表
|
const supplierList = ref([
|
{ value: "1", label: "供应商A" },
|
{ value: "2", label: "供应商B" },
|
{ value: "3", label: "供应商C" }
|
]);
|
|
// 订单状态列表
|
const orderStatusList = ref([
|
{ value: "received", label: "已收货" },
|
{ value: "partial_received", label: "部分收货" },
|
{ value: "quality_issue", label: "质量问题" }
|
]);
|
|
// 退货原因列表
|
const returnReasonList = ref([
|
{ value: "质量不合格", label: "质量不合格" },
|
{ value: "交货滞后", label: "交货滞后" },
|
{ value: "规格不符", label: "规格不符" },
|
{ value: "数量不符", label: "数量不符" },
|
{ value: "其他原因", label: "其他原因" }
|
]);
|
|
// 操作员列表
|
const operatorList = ref([
|
{ value: "1", label: "陈志强" },
|
{ value: "2", label: "刘美玲" },
|
{ value: "3", label: "王建国" }
|
]);
|
|
// 模拟采购订单数据
|
const mockOrderData = [
|
{
|
id: "1",
|
orderNo: "CG20241201001",
|
supplierName: "供应商A",
|
orderDate: "2024-12-01",
|
coalName: "无烟煤",
|
orderQuantity: 100,
|
receivedQuantity: 80,
|
status: "partial_received",
|
unitPrice: 800
|
},
|
{
|
id: "2",
|
orderNo: "CG20241201002",
|
supplierName: "供应商A",
|
orderDate: "2024-12-01",
|
coalName: "烟煤",
|
orderQuantity: 50,
|
receivedQuantity: 50,
|
status: "quality_issue",
|
unitPrice: 750
|
},
|
{
|
id: "3",
|
orderNo: "CG20241201003",
|
supplierName: "供应商B",
|
orderDate: "2024-12-01",
|
coalName: "褐煤",
|
orderQuantity: 80,
|
receivedQuantity: 60,
|
status: "partial_received",
|
unitPrice: 600
|
}
|
];
|
|
// 获取订单状态类型
|
const getOrderStatusType = (status) => {
|
const statusMap = {
|
received: "success",
|
partial_received: "warning",
|
quality_issue: "danger"
|
};
|
return statusMap[status] || "";
|
};
|
|
// 获取订单状态文本
|
const getOrderStatusText = (status) => {
|
const statusMap = {
|
received: "已收货",
|
partial_received: "部分收货",
|
quality_issue: "质量问题"
|
};
|
return statusMap[status] || status;
|
};
|
|
// 供应商变化处理
|
const handleSupplierChange = () => {
|
searchOrders();
|
};
|
|
// 查询订单
|
const searchOrders = () => {
|
// 模拟API调用
|
orderList.value = mockOrderData.filter(order => {
|
if (searchForm.supplierId && order.supplierName !== supplierList.value.find(s => s.value === searchForm.supplierId)?.label) {
|
return false;
|
}
|
if (searchForm.orderStatus && order.status !== searchForm.orderStatus) {
|
return false;
|
}
|
return true;
|
});
|
};
|
|
// 重置搜索
|
const resetSearch = () => {
|
Object.assign(searchForm, {
|
supplierId: "",
|
orderStatus: ""
|
});
|
searchOrders();
|
};
|
|
// 订单选择变化
|
const handleOrderSelectionChange = (selection) => {
|
selectedOrders.value = selection;
|
};
|
|
// 预览退货商品
|
const previewReturnItems = computed(() => {
|
return selectedOrders.value.map(order => ({
|
...order,
|
returnQuantity: order.status === 'quality_issue' ? order.receivedQuantity : (order.orderQuantity - order.receivedQuantity)
|
}));
|
});
|
|
// 更新退货数量
|
const updateReturnQuantity = (index) => {
|
const item = previewReturnItems.value[index];
|
if (item.returnQuantity > item.receivedQuantity) {
|
item.returnQuantity = item.receivedQuantity;
|
ElMessage.warning("退货数量不能超过已收货数量");
|
}
|
};
|
|
// 计算总退货数量
|
const getTotalReturnQuantity = () => {
|
return previewReturnItems.value.reduce((total, item) => total + (item.returnQuantity || 0), 0);
|
};
|
|
// 计算总退货金额
|
const getTotalReturnAmount = () => {
|
return previewReturnItems.value.reduce((total, item) => {
|
return total + ((item.returnQuantity || 0) * item.unitPrice);
|
}, 0).toFixed(2);
|
};
|
|
// 生成退货单
|
const generateReturnOrder = async () => {
|
if (!returnConfig.returnReason) {
|
ElMessage.warning("请选择退货原因");
|
return;
|
}
|
if (!returnConfig.operatorId) {
|
ElMessage.warning("请选择操作员");
|
return;
|
}
|
|
generateLoading.value = true;
|
|
try {
|
// 模拟生成退货单
|
await new Promise(resolve => setTimeout(resolve, 1000));
|
|
const returnOrder = {
|
returnNo: `TH${Date.now()}`,
|
supplierName: selectedOrders.value[0]?.supplierName,
|
returnDate: new Date().toISOString().split('T')[0],
|
operatorName: operatorList.value.find(op => op.value === returnConfig.operatorId)?.label,
|
returnReason: returnConfig.returnReason,
|
returnQuantity: getTotalReturnQuantity(),
|
returnAmount: getTotalReturnAmount(),
|
status: "draft",
|
createTime: new Date().toLocaleString(),
|
remark: returnConfig.remark,
|
returnItems: previewReturnItems.value.map(item => ({
|
coalId: item.id,
|
coalName: item.coalName,
|
specification: "标准规格",
|
quantity: item.returnQuantity,
|
unitPrice: item.unitPrice
|
}))
|
};
|
|
ElMessage.success("退货单生成成功");
|
emit('success', returnOrder);
|
handleClose();
|
} catch (error) {
|
ElMessage.error("生成退货单失败");
|
} finally {
|
generateLoading.value = false;
|
}
|
};
|
|
// 关闭对话框
|
const handleClose = () => {
|
emit('update:dialogGenerateVisible', false);
|
// 重置数据
|
Object.assign(searchForm, {
|
supplierId: "",
|
orderStatus: ""
|
});
|
Object.assign(returnConfig, {
|
returnReason: "",
|
operatorId: "",
|
remark: ""
|
});
|
selectedOrders.value = [];
|
orderList.value = mockOrderData;
|
};
|
|
// 初始化数据
|
watch(() => props.dialogGenerateVisible, (visible) => {
|
if (visible) {
|
orderList.value = mockOrderData;
|
}
|
}, { immediate: true });
|
</script>
|
|
<style scoped>
|
.generate-container {
|
padding: 0;
|
}
|
|
.select-card,
|
.config-card,
|
.preview-card {
|
margin-bottom: 20px;
|
}
|
|
.select-card:last-child,
|
.config-card:last-child,
|
.preview-card:last-child {
|
margin-bottom: 0;
|
}
|
|
.card-header {
|
font-weight: bold;
|
font-size: 16px;
|
}
|
|
.search-form {
|
margin-bottom: 20px;
|
}
|
|
.config-form {
|
padding: 20px 0;
|
}
|
|
.no-selection {
|
text-align: center;
|
padding: 40px 0;
|
}
|
|
.preview-content {
|
padding: 20px 0;
|
}
|
|
.preview-summary {
|
margin-top: 15px;
|
text-align: right;
|
padding: 10px;
|
background-color: #f5f7fa;
|
border-radius: 4px;
|
}
|
|
.summary-item {
|
margin-left: 20px;
|
font-size: 14px;
|
}
|
|
.summary-item strong {
|
color: #409eff;
|
font-size: 16px;
|
}
|
|
.dialog-footer {
|
text-align: right;
|
}
|
</style>
|