From c65e1446d2d386c4e6baef2fcc606bdd6de90576 Mon Sep 17 00:00:00 2001
From: spring <2396852758@qq.com>
Date: 星期四, 28 八月 2025 14:02:59 +0800
Subject: [PATCH] 采购退货单
---
src/views/sales/components/GenerateReturnDialog.vue | 528 +++++++++++++++++
src/views/sales/purchaseReturn.vue | 462 +++++++++++++++
src/views/sales/components/PurchaseReturnDialog.vue | 453 +++++++++++++++
src/views/sales/components/PurchaseReturnViewDialog.vue | 324 ++++++++++
4 files changed, 1,767 insertions(+), 0 deletions(-)
diff --git a/src/views/sales/components/GenerateReturnDialog.vue b/src/views/sales/components/GenerateReturnDialog.vue
new file mode 100644
index 0000000..ff6a7bd
--- /dev/null
+++ b/src/views/sales/components/GenerateReturnDialog.vue
@@ -0,0 +1,528 @@
+<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: "渚涘簲鍟咥" },
+ { value: "2", label: "渚涘簲鍟咮" },
+ { value: "3", label: "渚涘簲鍟咰" }
+]);
+
+// 璁㈠崟鐘舵�佸垪琛�
+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: "渚涘簲鍟咥",
+ orderDate: "2024-12-01",
+ coalName: "鏃犵儫鐓�",
+ orderQuantity: 100,
+ receivedQuantity: 80,
+ status: "partial_received",
+ unitPrice: 800
+ },
+ {
+ id: "2",
+ orderNo: "CG20241201002",
+ supplierName: "渚涘簲鍟咥",
+ orderDate: "2024-12-01",
+ coalName: "鐑熺叅",
+ orderQuantity: 50,
+ receivedQuantity: 50,
+ status: "quality_issue",
+ unitPrice: 750
+ },
+ {
+ id: "3",
+ orderNo: "CG20241201003",
+ supplierName: "渚涘簲鍟咮",
+ 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>
diff --git a/src/views/sales/components/PurchaseReturnDialog.vue b/src/views/sales/components/PurchaseReturnDialog.vue
new file mode 100644
index 0000000..3914ad7
--- /dev/null
+++ b/src/views/sales/components/PurchaseReturnDialog.vue
@@ -0,0 +1,453 @@
+<template>
+ <el-dialog
+ :model-value="dialogFormVisible"
+ @update:model-value="$emit('update:dialogFormVisible', $event)"
+ :title="title"
+ width="1000px"
+ :close-on-click-modal="false"
+ @close="handleClose"
+ >
+ <el-form
+ ref="formRef"
+ :model="formData"
+ :rules="rules"
+ label-width="120px"
+ class="purchase-return-form"
+ >
+ <el-row :gutter="20">
+ <el-col :span="12">
+ <el-form-item label="渚涘簲鍟�" prop="supplierId">
+ <el-select
+ v-model="formData.supplierId"
+ placeholder="璇烽�夋嫨渚涘簲鍟�"
+ style="width: 100%"
+ filterable
+ >
+ <el-option
+ :label="item.label"
+ v-for="item in supplierList"
+ :key="item.value"
+ :value="item.value"
+ />
+ </el-select>
+ </el-form-item>
+ </el-col>
+ <el-col :span="12">
+ <el-form-item label="鍗曟嵁鏃ユ湡" prop="returnDate">
+ <el-date-picker
+ v-model="formData.returnDate"
+ type="date"
+ placeholder="璇烽�夋嫨鍗曟嵁鏃ユ湡"
+ format="YYYY-MM-DD"
+ value-format="YYYY-MM-DD"
+ style="width: 100%"
+ />
+ </el-form-item>
+ </el-col>
+ </el-row>
+
+ <el-row :gutter="20">
+ <el-col :span="12">
+ <el-form-item label="鎿嶄綔鍛�" prop="operatorId">
+ <el-select
+ v-model="formData.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-col :span="12">
+ <el-form-item label="閫�璐у師鍥�" prop="returnReason">
+ <el-select
+ v-model="formData.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-row>
+
+ <el-row :gutter="20">
+ <el-col :span="12">
+ <el-form-item label="閫�璐ф暟閲�" prop="returnQuantity">
+ <el-input
+ v-model.number="formData.returnQuantity"
+ placeholder="璇疯緭鍏ラ��璐ф暟閲�"
+ style="width: 100%"
+ >
+ <template v-slot:suffix>
+ <span>鍚�</span>
+ </template>
+ </el-input>
+ </el-form-item>
+ </el-col>
+ <el-col :span="12">
+ <el-form-item label="閫�璐ч噾棰�" prop="returnAmount">
+ <el-input
+ v-model.number="formData.returnAmount"
+ placeholder="璇疯緭鍏ラ��璐ч噾棰�"
+ style="width: 100%"
+ >
+ <template v-slot:suffix>
+ <span>鍏�</span>
+ </template>
+ </el-input>
+ </el-form-item>
+ </el-col>
+ </el-row>
+
+ <el-form-item label="閫�璐у晢鍝佷俊鎭�" prop="returnItems">
+ <div class="return-items-container">
+ <div class="return-items-header">
+ <span>鍟嗗搧鏄庣粏</span>
+ <el-button type="primary" size="small" @click="addReturnItem">
+ 娣诲姞鍟嗗搧
+ </el-button>
+ </div>
+ <el-table :data="formData.returnItems" border style="width: 100%">
+ <el-table-column label="鍟嗗搧鍚嶇О" width="180">
+ <template #default="scope">
+ <el-select
+ v-model="scope.row.coalId"
+ placeholder="璇烽�夋嫨鍟嗗搧"
+ style="width: 100%"
+ filterable
+ >
+ <el-option
+ :label="item.label"
+ v-for="item in coalList"
+ :key="item.value"
+ :value="item.value"
+ />
+ </el-select>
+ </template>
+ </el-table-column>
+ <el-table-column label="瑙勬牸鍨嬪彿" width="120">
+ <template #default="scope">
+ <el-input
+ v-model="scope.row.specification"
+ placeholder="瑙勬牸鍨嬪彿"
+ />
+ </template>
+ </el-table-column>
+ <el-table-column label="鏁伴噺" width="120">
+ <template #default="scope">
+ <el-input
+ v-model.number="scope.row.quantity"
+ placeholder="鏁伴噺"
+ type="number"
+ >
+ <template v-slot:suffix>
+ <span>鍚�</span>
+ </template>
+ </el-input>
+ </template>
+ </el-table-column>
+ <el-table-column label="鍗曚环" width="120">
+ <template #default="scope">
+ <el-input
+ v-model.number="scope.row.unitPrice"
+ placeholder="鍗曚环"
+ type="number"
+ >
+ <template v-slot:suffix>
+ <span>鍏�/鍚�</span>
+ </template>
+ </el-input>
+ </template>
+ </el-table-column>
+ <el-table-column label="灏忚" width="120">
+ <template #default="scope">
+ <span>{{ (scope.row.quantity * scope.row.unitPrice).toFixed(2) }} 鍏�</span>
+ </template>
+ </el-table-column>
+ <el-table-column label="鎿嶄綔" width="80">
+ <template #default="scope">
+ <el-button
+ type="danger"
+ size="small"
+ @click="removeReturnItem(scope.$index)"
+ >
+ 鍒犻櫎
+ </el-button>
+ </template>
+ </el-table-column>
+ </el-table>
+ </div>
+ </el-form-item>
+
+ <el-form-item label="澶囨敞" prop="remark">
+ <el-input
+ v-model="formData.remark"
+ type="textarea"
+ :rows="3"
+ placeholder="璇疯緭鍏ュ娉ㄤ俊鎭�"
+ />
+ </el-form-item>
+ </el-form>
+
+ <template #footer>
+ <div class="dialog-footer">
+ <el-button @click="handleClose">鍙栨秷</el-button>
+ <el-button type="primary" @click="handleSubmit" :loading="submitLoading">
+ 鎻愪氦瀹℃牳
+ </el-button>
+ </div>
+ </template>
+ </el-dialog>
+</template>
+
+<script setup>
+import { ref, reactive, watch, nextTick } from "vue";
+import { ElMessage } from "element-plus";
+
+// Props
+const props = defineProps({
+ dialogFormVisible: {
+ type: Boolean,
+ default: false
+ },
+ form: {
+ type: Object,
+ default: () => ({})
+ },
+ title: {
+ type: String,
+ default: ""
+ },
+ isEdit: {
+ type: Boolean,
+ default: false
+ }
+});
+
+// Emits
+const emit = defineEmits(['update:dialogFormVisible', 'update:form', 'submit', 'success']);
+
+// 鍝嶅簲寮忔暟鎹�
+const formRef = ref(null);
+const submitLoading = ref(false);
+
+// 琛ㄥ崟鏁版嵁
+const formData = reactive({
+ supplierId: "",
+ returnDate: "",
+ operatorId: "",
+ returnReason: "",
+ returnQuantity: "",
+ returnAmount: "",
+ returnItems: [],
+ remark: ""
+});
+
+// 鍒濆鍖栬〃鍗曟暟鎹�
+const initFormData = () => {
+ Object.assign(formData, {
+ supplierId: "",
+ returnDate: "",
+ operatorId: "",
+ returnReason: "",
+ returnQuantity: "",
+ returnAmount: "",
+ returnItems: [],
+ remark: ""
+ });
+};
+
+// 渚涘簲鍟嗗垪琛�
+const supplierList = ref([
+ { value: "1", label: "渚涘簲鍟咥" },
+ { value: "2", label: "渚涘簲鍟咮" },
+ { value: "3", label: "渚涘簲鍟咰" }
+]);
+
+// 鎿嶄綔鍛樺垪琛�
+const operatorList = ref([
+ { value: "1", label: "闄堝織寮�" },
+ { value: "2", label: "鍒樼編鐜�" },
+ { value: "3", label: "鐜嬪缓鍥�" }
+]);
+
+// 閫�璐у師鍥犲垪琛�
+const returnReasonList = ref([
+ { value: "璐ㄩ噺涓嶅悎鏍�", label: "璐ㄩ噺涓嶅悎鏍�" },
+ { value: "浜よ揣婊炲悗", label: "浜よ揣婊炲悗" },
+ { value: "瑙勬牸涓嶇", label: "瑙勬牸涓嶇" },
+ { value: "鏁伴噺涓嶇", label: "鏁伴噺涓嶇" },
+ { value: "鍏朵粬鍘熷洜", label: "鍏朵粬鍘熷洜" }
+]);
+
+// 鍟嗗搧鍒楄〃
+const coalList = ref([
+ { value: "1", label: "鏃犵儫鐓�" },
+ { value: "2", label: "鐑熺叅" },
+ { value: "3", label: "瑜愮叅" },
+ { value: "4", label: "鐒︾叅" }
+]);
+
+// 琛ㄥ崟楠岃瘉瑙勫垯
+const rules = {
+ supplierId: [
+ { required: true, message: "璇烽�夋嫨渚涘簲鍟�", trigger: "change" }
+ ],
+ returnDate: [
+ { required: true, message: "璇烽�夋嫨鍗曟嵁鏃ユ湡", trigger: "change" }
+ ],
+ operatorId: [
+ { required: true, message: "璇烽�夋嫨鎿嶄綔鍛�", trigger: "change" }
+ ],
+ returnReason: [
+ { required: true, message: "璇烽�夋嫨閫�璐у師鍥�", trigger: "change" }
+ ],
+ returnQuantity: [
+ { required: true, message: "璇疯緭鍏ラ��璐ф暟閲�", trigger: "blur" },
+ { type: "number", min: 0, message: "鏁伴噺蹇呴』澶т簬0", trigger: "blur" }
+ ],
+ returnItems: [
+ {
+ type: "array",
+ required: true,
+ message: "璇疯嚦灏戞坊鍔犱竴涓��璐у晢鍝�",
+ trigger: "change",
+ validator: (rule, value, callback) => {
+ if (!value || value.length === 0) {
+ callback(new Error("璇疯嚦灏戞坊鍔犱竴涓��璐у晢鍝�"));
+ } else {
+ callback();
+ }
+ }
+ }
+ ]
+};
+
+// 鐩戝惉琛ㄥ崟鏁版嵁鍙樺寲
+watch(() => props.form, (newVal) => {
+ Object.assign(formData, newVal);
+ if (!formData.returnItems || formData.returnItems.length === 0) {
+ formData.returnItems = [];
+ }
+}, { deep: true, immediate: true });
+
+// 娣诲姞閫�璐у晢鍝�
+const addReturnItem = () => {
+ formData.returnItems.push({
+ coalId: "",
+ specification: "",
+ quantity: 0,
+ unitPrice: 0
+ });
+};
+
+// 鍒犻櫎閫�璐у晢鍝�
+const removeReturnItem = (index) => {
+ formData.returnItems.splice(index, 1);
+};
+
+// 鍏抽棴瀵硅瘽妗�
+const handleClose = () => {
+ emit('update:dialogFormVisible', false);
+ formRef.value?.resetFields();
+};
+
+// 鎻愪氦琛ㄥ崟
+const handleSubmit = async () => {
+ if (!formRef.value) return;
+
+ try {
+ await formRef.value.validate();
+
+ // 楠岃瘉閫�璐у晢鍝佷俊鎭�
+ if (formData.returnItems.length === 0) {
+ ElMessage.warning("璇疯嚦灏戞坊鍔犱竴涓��璐у晢鍝�");
+ return;
+ }
+
+ for (let item of formData.returnItems) {
+ if (!item.coalId) {
+ ElMessage.warning("璇烽�夋嫨鍟嗗搧");
+ return;
+ }
+ if (!item.quantity || item.quantity <= 0) {
+ ElMessage.warning("璇疯緭鍏ユ湁鏁堢殑鍟嗗搧鏁伴噺");
+ return;
+ }
+ }
+
+ submitLoading.value = true;
+
+ // 妯℃嫙鎻愪氦
+ setTimeout(() => {
+ submitLoading.value = false;
+ ElMessage.success("鎻愪氦鎴愬姛");
+ emit('submit', { ...formData });
+ handleClose();
+ }, 1000);
+
+ } catch (error) {
+ console.error('琛ㄥ崟楠岃瘉澶辫触:', error);
+ }
+};
+
+// 璁$畻鎬绘暟閲�
+const calculateTotalQuantity = () => {
+ return formData.returnItems.reduce((total, item) => total + (item.quantity || 0), 0);
+};
+
+// 璁$畻鎬婚噾棰�
+const calculateTotalAmount = () => {
+ return formData.returnItems.reduce((total, item) => {
+ return total + ((item.quantity || 0) * (item.unitPrice || 0));
+ }, 0);
+};
+
+// 鐩戝惉閫�璐у晢鍝佸彉鍖栵紝鑷姩璁$畻鎬绘暟閲忓拰鎬婚噾棰�
+watch(() => formData.returnItems, () => {
+ formData.returnQuantity = calculateTotalQuantity();
+ formData.returnAmount = calculateTotalAmount();
+}, { deep: true });
+</script>
+
+<style scoped>
+.purchase-return-form {
+ padding: 20px 0;
+}
+
+.return-items-container {
+ border: 1px solid #dcdfe6;
+ border-radius: 4px;
+ padding: 15px;
+}
+
+.return-items-header {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ margin-bottom: 15px;
+ font-weight: bold;
+}
+
+.dialog-footer {
+ text-align: right;
+}
+
+.el-table {
+ margin-top: 10px;
+}
+</style>
diff --git a/src/views/sales/components/PurchaseReturnViewDialog.vue b/src/views/sales/components/PurchaseReturnViewDialog.vue
new file mode 100644
index 0000000..529b682
--- /dev/null
+++ b/src/views/sales/components/PurchaseReturnViewDialog.vue
@@ -0,0 +1,324 @@
+<template>
+ <el-dialog
+ :model-value="dialogViewVisible"
+ @update:model-value="$emit('update:dialogViewVisible', $event)"
+ :title="title"
+ width="900px"
+ :close-on-click-modal="false"
+ >
+ <div class="view-container">
+ <!-- 鍩烘湰淇℃伅 -->
+ <el-card class="info-card" shadow="never">
+ <template #header>
+ <div class="card-header">
+ <span>鍩烘湰淇℃伅</span>
+ </div>
+ </template>
+ <el-descriptions :column="2" border>
+ <el-descriptions-item label="閫�璐у崟鍙�">
+ {{ form.returnNo || '-' }}
+ </el-descriptions-item>
+ <el-descriptions-item label="渚涘簲鍟�">
+ {{ form.supplierName || '-' }}
+ </el-descriptions-item>
+ <el-descriptions-item label="鍗曟嵁鏃ユ湡">
+ {{ form.returnDate || '-' }}
+ </el-descriptions-item>
+ <el-descriptions-item label="鎿嶄綔鍛�">
+ {{ form.operatorName || '-' }}
+ </el-descriptions-item>
+ <el-descriptions-item label="閫�璐у師鍥�">
+ {{ form.returnReason || '-' }}
+ </el-descriptions-item>
+ <el-descriptions-item label="鐘舵��">
+ <el-tag :type="getStatusType(form.status)">
+ {{ getStatusText(form.status) }}
+ </el-tag>
+ </el-descriptions-item>
+ <el-descriptions-item label="閫�璐ф暟閲�">
+ {{ form.returnQuantity || 0 }} 鍚�
+ </el-descriptions-item>
+ <el-descriptions-item label="閫�璐ч噾棰�">
+ {{ form.returnAmount || 0 }} 鍏�
+ </el-descriptions-item>
+ <el-descriptions-item label="鍒涘缓鏃堕棿" :span="2">
+ {{ form.createTime || '-' }}
+ </el-descriptions-item>
+ <el-descriptions-item label="澶囨敞" :span="2">
+ {{ form.remark || '-' }}
+ </el-descriptions-item>
+ </el-descriptions>
+ </el-card>
+
+ <!-- 閫�璐у晢鍝佹槑缁� -->
+ <el-card class="info-card" shadow="never">
+ <template #header>
+ <div class="card-header">
+ <span>閫�璐у晢鍝佹槑缁�</span>
+ </div>
+ </template>
+ <el-table :data="form.returnItems || []" border style="width: 100%">
+ <el-table-column label="搴忓彿" type="index" width="60" />
+ <el-table-column label="鍟嗗搧鍚嶇О" prop="coalName" width="150" />
+ <el-table-column label="瑙勬牸鍨嬪彿" prop="specification" width="150" />
+ <el-table-column label="鏁伴噺" prop="quantity" width="100">
+ <template #default="scope">
+ {{ scope.row.quantity || 0 }} 鍚�
+ </template>
+ </el-table-column>
+ <el-table-column label="鍗曚环" prop="unitPrice" width="120">
+ <template #default="scope">
+ {{ scope.row.unitPrice || 0 }} 鍏�/鍚�
+ </template>
+ </el-table-column>
+ <el-table-column label="灏忚" width="120">
+ <template #default="scope">
+ {{ ((scope.row.quantity || 0) * (scope.row.unitPrice || 0)).toFixed(2) }} 鍏�
+ </template>
+ </el-table-column>
+ </el-table>
+ <div class="table-summary">
+ <span class="summary-item">
+ 鎬绘暟閲忥細<strong>{{ getTotalQuantity() }} 鍚�</strong>
+ </span>
+ <span class="summary-item">
+ 鎬婚噾棰濓細<strong>{{ getTotalAmount() }} 鍏�</strong>
+ </span>
+ </div>
+ </el-card>
+
+ <!-- 瀹℃壒娴佺▼ -->
+ <el-card class="info-card" shadow="never">
+ <template #header>
+ <div class="card-header">
+ <span>瀹℃壒娴佺▼</span>
+ </div>
+ </template>
+ <el-timeline>
+ <el-timeline-item
+ v-for="(activity, index) in approvalFlow"
+ :key="index"
+ :timestamp="activity.timestamp"
+ :type="activity.type"
+ >
+ <h4>{{ activity.title }}</h4>
+ <p>{{ activity.content }}</p>
+ <p v-if="activity.operator">鎿嶄綔浜猴細{{ activity.operator }}</p>
+ </el-timeline-item>
+ </el-timeline>
+ </el-card>
+ </div>
+
+ <template #footer>
+ <div class="dialog-footer">
+ <el-button @click="handleClose">鍏抽棴</el-button>
+ </div>
+ </template>
+ </el-dialog>
+</template>
+
+<script setup>
+import { computed } from "vue";
+
+// Props
+const props = defineProps({
+ dialogViewVisible: {
+ type: Boolean,
+ default: false
+ },
+ form: {
+ type: Object,
+ default: () => ({})
+ },
+ title: {
+ type: String,
+ default: "閫�璐у崟璇︽儏"
+ }
+});
+
+// Emits
+const emit = defineEmits(['update:dialogViewVisible']);
+
+// 鑾峰彇鐘舵�佺被鍨�
+const getStatusType = (status) => {
+ const statusMap = {
+ draft: "",
+ pending: "warning",
+ approved: "success",
+ rejected: "danger",
+ completed: "info"
+ };
+ return statusMap[status] || "";
+};
+
+// 鑾峰彇鐘舵�佹枃鏈�
+const getStatusText = (status) => {
+ const statusMap = {
+ draft: "鑽夌",
+ pending: "寰呭鏍�",
+ approved: "宸插鏍�",
+ rejected: "宸叉嫆缁�",
+ completed: "宸插畬鎴�"
+ };
+ return statusMap[status] || status;
+};
+
+// 璁$畻鎬绘暟閲�
+const getTotalQuantity = () => {
+ if (!props.form.returnItems || props.form.returnItems.length === 0) {
+ return 0;
+ }
+ return props.form.returnItems.reduce((total, item) => total + (item.quantity || 0), 0);
+};
+
+// 璁$畻鎬婚噾棰�
+const getTotalAmount = () => {
+ if (!props.form.returnItems || props.form.returnItems.length === 0) {
+ return 0;
+ }
+ return props.form.returnItems.reduce((total, item) => {
+ return total + ((item.quantity || 0) * (item.unitPrice || 0));
+ }, 0).toFixed(2);
+};
+
+// 瀹℃壒娴佺▼鏁版嵁
+const approvalFlow = computed(() => {
+ const flow = [];
+
+ // 鍒涘缓
+ flow.push({
+ title: "鍒涘缓閫�璐у崟",
+ content: "閫�璐у崟宸插垱寤猴紝绛夊緟鎻愪氦瀹℃牳",
+ timestamp: props.form.createTime || new Date().toLocaleString(),
+ operator: props.form.operatorName || "绯荤粺",
+ type: "primary"
+ });
+
+ // 鏍规嵁鐘舵�佹坊鍔犲鎵规祦绋�
+ if (props.form.status === "pending") {
+ flow.push({
+ title: "鎻愪氦瀹℃牳",
+ content: "閫�璐у崟宸叉彁浜わ紝绛夊緟瀹℃牳",
+ timestamp: new Date().toLocaleString(),
+ operator: props.form.operatorName || "绯荤粺",
+ type: "warning"
+ });
+ } else if (props.form.status === "approved") {
+ flow.push({
+ title: "鎻愪氦瀹℃牳",
+ content: "閫�璐у崟宸叉彁浜わ紝绛夊緟瀹℃牳",
+ timestamp: new Date().toLocaleString(),
+ operator: props.form.operatorName || "绯荤粺",
+ type: "warning"
+ });
+ flow.push({
+ title: "瀹℃牳閫氳繃",
+ content: "閫�璐у崟瀹℃牳閫氳繃",
+ timestamp: new Date().toLocaleString(),
+ operator: "瀹℃牳鍛�",
+ type: "success"
+ });
+ } else if (props.form.status === "rejected") {
+ flow.push({
+ title: "鎻愪氦瀹℃牳",
+ content: "閫�璐у崟宸叉彁浜わ紝绛夊緟瀹℃牳",
+ timestamp: new Date().toLocaleString(),
+ operator: props.form.operatorName || "绯荤粺",
+ type: "warning"
+ });
+ flow.push({
+ title: "瀹℃牳鎷掔粷",
+ content: "閫�璐у崟瀹℃牳琚嫆缁�",
+ timestamp: new Date().toLocaleString(),
+ operator: "瀹℃牳鍛�",
+ type: "danger"
+ });
+ } else if (props.form.status === "completed") {
+ flow.push({
+ title: "鎻愪氦瀹℃牳",
+ content: "閫�璐у崟宸叉彁浜わ紝绛夊緟瀹℃牳",
+ timestamp: new Date().toLocaleString(),
+ operator: props.form.operatorName || "绯荤粺",
+ type: "warning"
+ });
+ flow.push({
+ title: "瀹℃牳閫氳繃",
+ content: "閫�璐у崟瀹℃牳閫氳繃",
+ timestamp: new Date().toLocaleString(),
+ operator: "瀹℃牳鍛�",
+ type: "success"
+ });
+ flow.push({
+ title: "閫�璐у畬鎴�",
+ content: "閫�璐ф祦绋嬪凡瀹屾垚",
+ timestamp: new Date().toLocaleString(),
+ operator: "绯荤粺",
+ type: "info"
+ });
+ }
+
+ return flow;
+});
+
+// 鍏抽棴瀵硅瘽妗�
+const handleClose = () => {
+ emit('update:dialogViewVisible', false);
+};
+</script>
+
+<style scoped>
+.view-container {
+ padding: 0;
+}
+
+.info-card {
+ margin-bottom: 20px;
+}
+
+.info-card:last-child {
+ margin-bottom: 0;
+}
+
+.card-header {
+ font-weight: bold;
+ font-size: 16px;
+}
+
+.table-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;
+}
+
+.el-timeline {
+ padding: 20px;
+}
+
+.el-timeline-item h4 {
+ margin: 0 0 8px 0;
+ font-size: 14px;
+ color: #303133;
+}
+
+.el-timeline-item p {
+ margin: 4px 0;
+ font-size: 12px;
+ color: #606266;
+}
+</style>
diff --git a/src/views/sales/purchaseReturn.vue b/src/views/sales/purchaseReturn.vue
new file mode 100644
index 0000000..b84cc10
--- /dev/null
+++ b/src/views/sales/purchaseReturn.vue
@@ -0,0 +1,462 @@
+<template>
+ <div class="app-container">
+ <el-form :inline="true" :model="queryParams" class="search-form">
+ <el-form-item label="閫�璐у崟鍙�">
+ <el-input
+ v-model="queryParams.returnNo"
+ placeholder="璇疯緭鍏ラ��璐у崟鍙�"
+ clearable
+ :style="{ width: '200px' }"
+ />
+ </el-form-item>
+ <el-form-item label="渚涘簲鍟�">
+ <el-select
+ v-model="queryParams.supplierId"
+ placeholder="璇烽�夋嫨渚涘簲鍟�"
+ clearable
+ :style="{ width: '200px' }"
+ >
+ <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="queryParams.status"
+ placeholder="璇烽�夋嫨鐘舵��"
+ clearable
+ :style="{ width: '150px' }"
+ >
+ <el-option
+ :label="item.label"
+ v-for="item in statusList"
+ :key="item.value"
+ :value="item.value"
+ />
+ </el-select>
+ </el-form-item>
+ <el-form-item label="鍗曟嵁鏃ユ湡">
+ <el-date-picker
+ v-model="queryParams.dateRange"
+ type="daterange"
+ range-separator="鑷�"
+ start-placeholder="寮�濮嬫棩鏈�"
+ end-placeholder="缁撴潫鏃ユ湡"
+ format="YYYY-MM-DD"
+ value-format="YYYY-MM-DD"
+ :style="{ width: '240px' }"
+ />
+ </el-form-item>
+ <el-form-item>
+ <el-button type="primary" @click="handleQuery">鏌ヨ</el-button>
+ <el-button @click="resetQuery">閲嶇疆</el-button>
+ </el-form-item>
+ </el-form>
+
+ <el-card>
+ <!-- 鎿嶄綔鎸夐挳鍖� -->
+ <el-row :gutter="24" class="table-toolbar" justify="space-between">
+ <el-button type="primary" :icon="Plus" @click="handleAdd">
+ 鏂板閫�璐у崟
+ </el-button>
+ <el-button type="success" :icon="Refresh" @click="handleGenerateReturn">
+ 涓�閿敓鎴愰��璐у崟
+ </el-button>
+ <el-button type="danger" :icon="Delete" @click="handleBatchDelete" :disabled="selectedIds.length === 0">
+ 鎵归噺鍒犻櫎
+ </el-button>
+ </el-row>
+
+ <!-- 琛ㄦ牸缁勪欢 -->
+ <el-table
+ v-loading="loading"
+ :data="tableData"
+ @selection-change="handleSelectionChange"
+ border
+ style="width: 100%"
+ >
+ <el-table-column type="selection" width="55" />
+ <el-table-column label="閫�璐у崟鍙�" prop="returnNo" width="180" />
+ <el-table-column label="渚涘簲鍟�" prop="supplierName" width="200" />
+ <el-table-column label="鍗曟嵁鏃ユ湡" prop="returnDate" width="120" />
+ <el-table-column label="鎿嶄綔鍛�" prop="operatorName" width="120" />
+ <el-table-column label="閫�璐у師鍥�" prop="returnReason" width="200" show-overflow-tooltip />
+ <el-table-column label="閫�璐ф暟閲�" prop="returnQuantity" width="120">
+ <template #default="scope">
+ {{ scope.row.returnQuantity }} 鍚�
+ </template>
+ </el-table-column>
+ <el-table-column label="鐘舵��" prop="status" width="100">
+ <template #default="scope">
+ <el-tag :type="getStatusType(scope.row.status)">
+ {{ getStatusText(scope.row.status) }}
+ </el-tag>
+ </template>
+ </el-table-column>
+ <el-table-column label="鍒涘缓鏃堕棿" prop="createTime" width="160" />
+ <el-table-column label="鎿嶄綔" width="200" fixed="right">
+ <template #default="scope">
+ <el-button
+ size="small"
+ type="primary"
+ @click="handleView(scope.row)"
+ >
+ 鏌ョ湅
+ </el-button>
+ <el-button
+ size="small"
+ type="warning"
+ @click="handleEdit(scope.row)"
+ v-if="scope.row.status === 'draft'"
+ >
+ 缂栬緫
+ </el-button>
+ <el-button
+ size="small"
+ type="danger"
+ @click="handleDelete(scope.row)"
+ v-if="scope.row.status === 'draft'"
+ >
+ 鍒犻櫎
+ </el-button>
+ </template>
+ </el-table-column>
+ </el-table>
+
+ <!-- 鍒嗛〉缁勪欢 -->
+ <pagination
+ v-if="total > 0"
+ :page="current"
+ :limit="pageSize"
+ :total="total"
+ @pagination="handlePagination"
+ :layout="'total, prev, pager, next, jumper'"
+ />
+ </el-card>
+
+ <!-- 鏂板/缂栬緫瀵硅瘽妗� -->
+ <PurchaseReturnDialog
+ v-model:dialogFormVisible="dialogFormVisible"
+ v-model:form="form"
+ :title="title"
+ :is-edit="isEdit"
+ @submit="handleSubmit"
+ @success="handleSuccess"
+ ref="purchaseReturnDialog"
+ />
+
+ <!-- 鏌ョ湅璇︽儏瀵硅瘽妗� -->
+ <PurchaseReturnViewDialog
+ v-model:dialogViewVisible="dialogViewVisible"
+ :form="viewForm"
+ title="閫�璐у崟璇︽儏"
+ />
+
+ <!-- 涓�閿敓鎴愰��璐у崟瀵硅瘽妗� -->
+ <GenerateReturnDialog
+ v-model:dialogGenerateVisible="dialogGenerateVisible"
+ @success="handleGenerateSuccess"
+ />
+ </div>
+</template>
+
+<script setup>
+import { ref, reactive, onMounted, getCurrentInstance } from "vue";
+import { ElMessage, ElMessageBox } from "element-plus";
+import { Plus, Edit, Delete, Refresh, View } from "@element-plus/icons-vue";
+import Pagination from "@/components/Pagination";
+import PurchaseReturnDialog from "./components/PurchaseReturnDialog.vue";
+import PurchaseReturnViewDialog from "./components/PurchaseReturnViewDialog.vue";
+import GenerateReturnDialog from "./components/GenerateReturnDialog.vue";
+
+// 鍝嶅簲寮忔暟鎹�
+const loading = ref(false);
+const tableData = ref([]);
+const selectedIds = ref([]);
+const current = ref(1);
+const pageSize = ref(10);
+const total = ref(0);
+const dialogFormVisible = ref(false);
+const dialogViewVisible = ref(false);
+const dialogGenerateVisible = ref(false);
+const isEdit = ref(false);
+const title = ref("");
+const form = ref({});
+const viewForm = ref({});
+
+// 鏌ヨ鍙傛暟
+const queryParams = reactive({
+ returnNo: "",
+ supplierId: "",
+ status: "",
+ dateRange: []
+});
+
+// 渚涘簲鍟嗗垪琛�
+const supplierList = ref([
+ { value: "1", label: "渚涘簲鍟咥" },
+ { value: "2", label: "渚涘簲鍟咮" },
+ { value: "3", label: "渚涘簲鍟咰" }
+]);
+
+// 鐘舵�佸垪琛�
+const statusList = ref([
+ { value: "draft", label: "鑽夌" },
+ { value: "pending", label: "寰呭鏍�" },
+ { value: "approved", label: "宸插鏍�" },
+ { value: "rejected", label: "宸叉嫆缁�" },
+ { value: "completed", label: "宸插畬鎴�" }
+]);
+
+// 妯℃嫙鏁版嵁
+const mockData = [
+ {
+ id: "1",
+ returnNo: "TH20241201001",
+ supplierName: "渚涘簲鍟咥",
+ returnDate: "2024-12-01",
+ operatorName: "闄堝織寮�",
+ returnReason: "璐ㄩ噺涓嶅悎鏍硷紝鐓よ川涓嶇鍚堣姹�",
+ returnQuantity: 50,
+ status: "pending",
+ createTime: "2024-12-01 10:00:00"
+ },
+ {
+ id: "2",
+ returnNo: "TH20241201002",
+ supplierName: "渚涘簲鍟咮",
+ returnDate: "2024-12-01",
+ operatorName: "鍒樼編鐜�",
+ returnReason: "浜よ揣婊炲悗锛屽奖鍝嶇敓浜ц鍒�",
+ returnQuantity: 30,
+ status: "approved",
+ createTime: "2024-12-01 14:30:00"
+ }
+];
+
+// 鑾峰彇鐘舵�佺被鍨�
+const getStatusType = (status) => {
+ const statusMap = {
+ draft: "",
+ pending: "warning",
+ approved: "success",
+ rejected: "danger",
+ completed: "info"
+ };
+ return statusMap[status] || "";
+};
+
+// 鑾峰彇鐘舵�佹枃鏈�
+const getStatusText = (status) => {
+ const statusMap = {
+ draft: "鑽夌",
+ pending: "寰呭鏍�",
+ approved: "宸插鏍�",
+ rejected: "宸叉嫆缁�",
+ completed: "宸插畬鎴�"
+ };
+ return statusMap[status] || status;
+};
+
+// 鏌ヨ
+const handleQuery = () => {
+ current.value = 1;
+ loadData();
+};
+
+// 閲嶇疆鏌ヨ
+const resetQuery = () => {
+ Object.assign(queryParams, {
+ returnNo: "",
+ supplierId: "",
+ status: "",
+ dateRange: []
+ });
+ handleQuery();
+};
+
+// 鍔犺浇鏁版嵁
+const loadData = () => {
+ loading.value = true;
+ // 妯℃嫙API璋冪敤
+ setTimeout(() => {
+ tableData.value = mockData;
+ total.value = mockData.length;
+ loading.value = false;
+ }, 500);
+};
+
+// 鍒嗛〉澶勭悊
+const handlePagination = (pagination) => {
+ current.value = pagination.page;
+ pageSize.value = pagination.limit;
+ loadData();
+};
+
+// 閫夋嫨鍙樺寲
+const handleSelectionChange = (selection) => {
+ selectedIds.value = selection.map(item => item.id);
+};
+
+// 鏂板
+const handleAdd = () => {
+ isEdit.value = false;
+ title.value = "鏂板閫�璐у崟";
+ form.value = {
+ supplierId: "",
+ returnDate: "",
+ operatorId: "",
+ returnReason: "",
+ returnQuantity: "",
+ returnAmount: "",
+ returnItems: [],
+ remark: ""
+ };
+ dialogFormVisible.value = true;
+};
+
+// 缂栬緫
+const handleEdit = (row) => {
+ isEdit.value = true;
+ title.value = "缂栬緫閫�璐у崟";
+ form.value = { ...row };
+ dialogFormVisible.value = true;
+};
+
+// 鏌ョ湅
+const handleView = (row) => {
+ viewForm.value = { ...row };
+ dialogViewVisible.value = true;
+};
+
+// 鍒犻櫎
+const handleDelete = (row) => {
+ ElMessageBox.confirm(
+ `纭畾瑕佸垹闄ら��璐у崟 ${row.returnNo} 鍚楋紵`,
+ "鎻愮ず",
+ {
+ confirmButtonText: "纭畾",
+ cancelButtonText: "鍙栨秷",
+ type: "warning"
+ }
+ ).then(() => {
+ // 妯℃嫙鍒犻櫎
+ const index = tableData.value.findIndex(item => item.id === row.id);
+ if (index > -1) {
+ tableData.value.splice(index, 1);
+ total.value--;
+ ElMessage.success("鍒犻櫎鎴愬姛");
+ }
+ });
+};
+
+// 鎵归噺鍒犻櫎
+const handleBatchDelete = () => {
+ if (selectedIds.value.length === 0) {
+ ElMessage.warning("璇烽�夋嫨瑕佸垹闄ょ殑璁板綍");
+ return;
+ }
+
+ ElMessageBox.confirm(
+ `纭畾瑕佸垹闄ら�変腑鐨� ${selectedIds.value.length} 鏉¤褰曞悧锛焋,
+ "鎻愮ず",
+ {
+ confirmButtonText: "纭畾",
+ cancelButtonText: "鍙栨秷",
+ type: "warning"
+ }
+ ).then(() => {
+ // 妯℃嫙鎵归噺鍒犻櫎
+ tableData.value = tableData.value.filter(item => !selectedIds.value.includes(item.id));
+ total.value = tableData.value.length;
+ selectedIds.value = [];
+ ElMessage.success("鎵归噺鍒犻櫎鎴愬姛");
+ });
+};
+
+// 涓�閿敓鎴愰��璐у崟
+const handleGenerateReturn = () => {
+ dialogGenerateVisible.value = true;
+};
+
+// 鎻愪氦琛ㄥ崟
+const handleSubmit = (formData) => {
+ if (isEdit.value) {
+ // 缂栬緫
+ const index = tableData.value.findIndex(item => item.id === formData.id);
+ if (index > -1) {
+ tableData.value[index] = { ...formData };
+ ElMessage.success("缂栬緫鎴愬姛");
+ }
+ } else {
+ // 鏂板
+ const newItem = {
+ id: Date.now().toString(),
+ returnNo: `TH${Date.now()}`,
+ supplierName: supplierList.value.find(item => item.value === formData.supplierId)?.label || "",
+ returnDate: formData.returnDate,
+ operatorName: "褰撳墠鐢ㄦ埛",
+ returnReason: formData.returnReason,
+ returnQuantity: formData.returnQuantity,
+ status: "draft",
+ createTime: new Date().toLocaleString()
+ };
+ tableData.value.unshift(newItem);
+ total.value++;
+ ElMessage.success("鏂板鎴愬姛");
+ }
+ dialogFormVisible.value = false;
+};
+
+// 琛ㄥ崟鎴愬姛鍥炶皟
+const handleSuccess = () => {
+ loadData();
+};
+
+// 鐢熸垚閫�璐у崟鎴愬姛鍥炶皟
+const handleGenerateSuccess = (returnOrder) => {
+ dialogGenerateVisible.value = false;
+ // 灏嗙敓鎴愮殑閫�璐у崟娣诲姞鍒板垪琛ㄤ腑
+ if (returnOrder) {
+ const newItem = {
+ id: Date.now().toString(),
+ returnNo: returnOrder.returnNo,
+ supplierName: returnOrder.supplierName,
+ returnDate: returnOrder.returnDate,
+ operatorName: returnOrder.operatorName,
+ returnReason: returnOrder.returnReason,
+ returnQuantity: returnOrder.returnQuantity,
+ status: returnOrder.status,
+ createTime: returnOrder.createTime,
+ returnItems: returnOrder.returnItems
+ };
+ tableData.value.unshift(newItem);
+ total.value++;
+ }
+ loadData();
+ ElMessage.success("閫�璐у崟鐢熸垚鎴愬姛");
+};
+
+// 椤甸潰鍔犺浇
+onMounted(() => {
+ loadData();
+});
+</script>
+
+<style scoped>
+.search-form {
+ margin-bottom: 20px;
+}
+
+.table-toolbar {
+ margin-bottom: 20px;
+}
+
+.el-card {
+ margin-bottom: 20px;
+}
+</style>
--
Gitblit v1.9.3