From eb956d7f1a0d174c0d55fccebfa4872d2abfbe94 Mon Sep 17 00:00:00 2001
From: huminmin <mac@MacBook-Pro.local>
Date: 星期五, 06 三月 2026 18:02:18 +0800
Subject: [PATCH] 增加采购退货单列表和新增页面

---
 src/views/salesManagement/returnOrder/index.vue |  294 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 294 insertions(+), 0 deletions(-)

diff --git a/src/views/salesManagement/returnOrder/index.vue b/src/views/salesManagement/returnOrder/index.vue
new file mode 100644
index 0000000..1165ed3
--- /dev/null
+++ b/src/views/salesManagement/returnOrder/index.vue
@@ -0,0 +1,294 @@
+<template>
+  <div class="app-container">
+    <div class="search-wrapper">
+      <el-form :model="searchForm" class="demo-form-inline">
+        <el-row :gutter="20">
+          <el-col :span="4">
+            <el-form-item>
+              <el-input v-model="searchForm.returnNo" placeholder="璇疯緭鍏ラ��璐у崟鍙�" clearable />
+            </el-form-item>
+          </el-col>
+          <el-col :span="4">
+            <el-form-item>
+              <el-input v-model="searchForm.customerName" placeholder="瀹㈡埛鍚嶇О" clearable />
+            </el-form-item>
+          </el-col>
+          <el-col :span="4">
+            <el-form-item>
+              <el-input v-model="searchForm.salesContractNo" placeholder="閿�鍞崟鍙�" clearable />
+            </el-form-item>
+          </el-col>
+          <el-col :span="4">
+            <el-form-item>
+              <el-input v-model="searchForm.shippingNo" placeholder="鍏宠仈鍑哄簱鍗曞彿" clearable />
+            </el-form-item>
+          </el-col>
+          <el-col :span="4">
+            <el-form-item>
+              <el-button type="primary" @click="handleQuery">鎼滅储</el-button>
+              <el-button @click="handleReset">閲嶇疆</el-button>
+            </el-form-item>
+          </el-col>
+        </el-row>
+      </el-form>
+    </div>
+    <div class="table_list">
+      <div class="table_header" style="display:flex;justify-content:space-between;align-items:center;">
+        <div>
+          <el-button type="primary" @click="openForm('add')">鏂板缓閿�鍞��璐�</el-button>
+        </div>
+        <div>
+          <el-button type="danger" plain @click="handleDelete">鍒犻櫎</el-button>
+          <el-button @click="columnsDialogVisible = true">鍒楄〃瀛楁</el-button>
+        </div>
+      </div>
+      <PIMTable
+        rowKey="id"
+        :column="visibleColumns"
+        :tableData="tableData"
+        :page="page"
+        :isSelection="true"
+        @selection-change="handleSelectionChange"
+        :tableLoading="tableLoading"
+        @pagination="pagination"
+      />
+    </div>
+    <form-dia ref="formDia" @close="handleQuery" />
+
+    <el-dialog v-model="columnsDialogVisible" title="鑷畾涔夋樉绀哄垪椤�" width="600px">
+      <div class="columns-tip">娉細鍒楄〃椤规樉绀轰笉寰楀皯浜�5椤癸紱鎷栧姩鍙充晶鎶婃墜鍙皟鏁存樉绀洪『搴�</div>
+      <ul class="columns-list">
+        <li v-for="(col, idx) in allColumns" :key="col.prop"
+            class="columns-item"
+            draggable="true"
+            @dragstart="onDragStart(idx)"
+            @dragover.prevent
+            @drop="onDrop(idx)">
+          <el-checkbox v-model="col.selected">{{ col.label }}</el-checkbox>
+          <span class="drag-handle">鈮�</span>
+        </li>
+      </ul>
+      <template #footer>
+        <el-button @click="resetColumns">鎭㈠榛樿</el-button>
+        <el-button type="primary" @click="saveColumns">淇濆瓨</el-button>
+      </template>
+    </el-dialog>
+  </div>
+</template>
+
+<script setup>
+import { reactive, ref, toRefs, computed, getCurrentInstance, nextTick, onMounted } from "vue";
+import { ElMessageBox } from "element-plus";
+import FormDia from "./components/formDia.vue";
+import { returnManagementList, returnManagementDel, returnManagementHandle } from "@/api/salesManagement/returnOrder.js";
+const { proxy } = getCurrentInstance();
+
+const formDia = ref();
+const openForm = (type, row) => {
+  nextTick(() => formDia.value?.openDialog(type, row));
+};
+
+const handleRowDelete = (row) => {
+  if (!row?.id) return;
+  ElMessageBox.confirm("璇ラ��璐у崟灏嗚鍒犻櫎锛屾槸鍚︾‘璁ゅ垹闄わ紵", "鍒犻櫎鎻愮ず", {
+    confirmButtonText: "纭",
+    cancelButtonText: "鍙栨秷",
+    type: "warning",
+  }).then(() => {
+    returnManagementDel({ ids: String(row.id) }).then(() => {
+      proxy.$modal.msgSuccess("鍒犻櫎鎴愬姛");
+      getList();
+    });
+  });
+};
+
+const handleRowHandle = (row) => {
+  if (!row?.id) return;
+  ElMessageBox.confirm("鏄惁澶勭悊璇ラ��璐у崟锛熷鐞嗗悗灏嗘棤娉曚慨鏀�", "澶勭悊鎻愮ず", {
+    confirmButtonText: "纭",
+    cancelButtonText: "鍙栨秷",
+    type: "warning",
+  }).then(() => {
+    returnManagementHandle({ returnManagementId: String(row.id) }).then(() => {
+      proxy.$modal.msgSuccess("澶勭悊鎴愬姛");
+      getList();
+    });
+  });
+}
+
+const data = reactive({
+  searchForm: {
+    returnNo: "",
+    status: "",
+    customerName: "",
+    salesContractNo: "",
+    salesman: "",
+    shippingNo: "",
+    projectName: "",
+    salesLedgerId: "",
+    makeTime: ""
+  }
+});
+const { searchForm } = toRefs(data);
+
+const documentStatusOptions = ref([
+  { label: "寰呭鏍�", value: 0 },
+  { label: "瀹℃牳涓�", value: 1 },
+  { label: "宸插鏍�", value: 2 }
+]);
+
+const defaultColumns = [
+  { label: "閫�璐у崟鍙�", prop: "returnNo", minWidth: 160 },
+  { label: "鍗曟嵁鐘舵��", prop: "status", minWidth: 120, formatData: (v) => ({ "0": "寰呭鏍�", "1": "瀹℃牳涓�", "2": "宸插鏍�" }[String(v)] ?? v) },
+  { label: "鍒跺崟鏃堕棿", prop: "makeTime", minWidth: 170 },
+  { label: "瀹㈡埛鍚嶇О", prop: "customerName", minWidth: 220 },
+  { label: "閿�鍞崟鍙�", prop: "salesContractNo", minWidth: 160 },
+  { label: "涓氬姟鍛�", prop: "salesman", minWidth: 120 },
+  { label: "鍏宠仈鍑哄簱鍗曞彿", prop: "shippingNo", minWidth: 170 },
+  { label: "椤圭洰鍚嶇О", prop: "projectName", minWidth: 180 },
+  { label: "椤圭洰闃舵", prop: "projectStage", minWidth: 120 },
+  { label: "鍒跺崟浜�", prop: "maker", minWidth: 120 },
+  { label: "缁撶畻浜�", prop: "settler", minWidth: 120 },
+  {
+    label: "鎿嶄綔",
+    prop: "operation",
+    dataType: "action",
+    align: "center",
+    fixed: "right",
+    width: 160,
+    operation: [
+      { name: "缂栬緫", disabled: (row) => row.status !== 0, type: "text", clickFun: (row) => openForm("edit", row) },
+      { name: "澶勭悊", disabled: (row) => row.status !== 0, type: "text", clickFun: (row) => handleRowHandle(row) },
+      { name: "鍒犻櫎", disabled: (row) => row.status !== 0, type: "text", clickFun: (row) => handleRowDelete(row) },
+    ],
+  },
+];
+const COLUMNS_KEY = "return_order_columns_v2";
+const columnsDialogVisible = ref(false);
+const allColumns = ref([]);
+
+const initColumns = () => {
+  const saved = localStorage.getItem(COLUMNS_KEY);
+  if (saved) {
+    try {
+      const parsed = JSON.parse(saved);
+      // 鍚堝苟榛樿鍒椾笌宸蹭繚瀛橀厤缃紝閬垮厤鍚庣画鏂板鍒椾涪澶�
+      const map = new Map(parsed.map(c => [c.prop, c]));
+      allColumns.value = defaultColumns.map(d => {
+        const found = map.get(d.prop);
+        return { ...d, selected: found ? !!found.selected : true };
+      });
+      // 浠ヤ繚瀛樼殑椤哄簭涓哄噯
+      const order = parsed.map(p => p.prop);
+      allColumns.value.sort((a, b) => order.indexOf(a.prop) - order.indexOf(b.prop));
+      return;
+    } catch {}
+  }
+  allColumns.value = defaultColumns.map(c => ({ ...c, selected: true }));
+};
+initColumns();
+
+const visibleColumns = computed(() => allColumns.value.filter(c => c.selected));
+
+let dragFrom = -1;
+const onDragStart = (idx) => {
+  dragFrom = idx;
+};
+const onDrop = (to) => {
+  if (dragFrom < 0 || dragFrom === to) return;
+  const arr = [...allColumns.value];
+  const [moved] = arr.splice(dragFrom, 1);
+  arr.splice(to, 0, moved);
+  allColumns.value = arr;
+  dragFrom = -1;
+};
+
+const resetColumns = () => {
+  allColumns.value = defaultColumns.map(c => ({ ...c, selected: true }));
+  localStorage.removeItem(COLUMNS_KEY);
+};
+const saveColumns = () => {
+  const toSave = allColumns.value.map(({ label, prop, width, selected }) => ({ label, prop, width, selected }));
+  localStorage.setItem(COLUMNS_KEY, JSON.stringify(toSave));
+  columnsDialogVisible.value = false;
+};
+
+const tableData = ref([]);
+const tableLoading = ref(false);
+const page = reactive({ current: 1, size: 10, total: 0 });
+const selectedRows = ref([]);
+const tableHeight = computed(() => "calc(100% - 80px)");
+
+const handleReset = () => {
+  Object.keys(searchForm.value).forEach(k => searchForm.value[k] = "");
+};
+const handleSelectionChange = (selection) => {
+  selectedRows.value = selection;
+};
+const handleQuery = () => {
+  page.current = 1;
+  getList();
+};
+const pagination = (obj) => {
+  page.current = obj.page;
+  page.size = obj.limit;
+  getList();
+};
+const getList = () => {
+  tableLoading.value = true;
+  returnManagementList({ ...searchForm.value, ...page }).then(res => {
+    tableLoading.value = false;
+    tableData.value = res?.data?.records || [];
+    page.total = res?.data?.total || 0;
+  }).finally(() => tableLoading.value = false);
+};
+const handleOut = () => {
+  ElMessageBox.alert("瀵煎嚭鍔熻兘寰呮帴鍏ユ帴鍙�", "鎻愮ず");
+};
+const handleDelete = () => {
+  let ids = [];
+  if (selectedRows.value.length === 0) {
+    proxy.$modal.msgWarning("璇烽�夋嫨鏁版嵁");
+    return;
+  }
+  ids = selectedRows.value.map(i => i.id);
+  ElMessageBox.confirm("閫変腑鐨勫唴瀹瑰皢琚垹闄わ紝鏄惁纭鍒犻櫎锛�", "鍒犻櫎鎻愮ず", {
+    confirmButtonText: "纭",
+    cancelButtonText: "鍙栨秷",
+    type: "warning",
+  }).then(() => {
+    returnManagementDel({ ids: ids.join(",") }).then(() => {
+      proxy.$modal.msgSuccess("鍒犻櫎鎴愬姛");
+      getList();
+    });
+  });
+};
+
+onMounted(() => {
+  getList();
+});
+</script>
+
+<style scoped lang="scss">
+.search-wrapper {
+  background: white;
+  padding: 1rem 1rem 0 1rem;
+  border: 8px;
+  border-radius: 16px;
+}
+.table_list {
+  height: calc(100vh - 230px);
+  min-height: 360px;
+  background: #fff;
+  margin-top: 20px;
+  display: flex;
+  flex-direction: column;
+}
+.columns-tip{color:#909399;margin-bottom:10px;font-size:12px;}
+.columns-list{list-style:none;padding:0;margin:0;max-height:360px;overflow:auto;}
+.columns-item{display:flex;justify-content:space-between;align-items:center;padding:8px 10px;border:1px solid #f0f0f0;border-radius:6px;margin-bottom:8px;cursor:move;background:#fff;}
+.columns-item .drag-handle{color:#909399;padding-left:12px;user-select:none;}
+.table_header {
+  margin-bottom: 15px;
+}
+</style>

--
Gitblit v1.9.3