From 377c0a70c094d024aeb0bb94f4b791c6d5530c1e Mon Sep 17 00:00:00 2001
From: gaoluyang <2820782392@qq.com>
Date: 星期四, 06 八月 2026 10:21:55 +0800
Subject: [PATCH] 新疆_马铃薯 1.不合格管理添加拒收逻辑

---
 src/views/salesManagement/returnOrder/components/detailDia.vue |  342 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 342 insertions(+), 0 deletions(-)

diff --git a/src/views/salesManagement/returnOrder/components/detailDia.vue b/src/views/salesManagement/returnOrder/components/detailDia.vue
new file mode 100644
index 0000000..ee94764
--- /dev/null
+++ b/src/views/salesManagement/returnOrder/components/detailDia.vue
@@ -0,0 +1,342 @@
+<template>
+  <el-dialog v-model="dialogVisible" title="閫�璐у崟璇︽儏" width="90%" @close="closeDia">
+    <div v-loading="loading">
+      <span class="descriptions">鍩烘湰淇℃伅</span>
+      <el-descriptions :column="4" border>
+        <el-descriptions-item label="閫�璐у崟鍙�">{{ detail.returnNo }}</el-descriptions-item>
+        <el-descriptions-item label="鍗曟嵁鐘舵��">
+          <el-tag :type="getStatusType(detail.status)">{{ getStatusText(detail.status) }}</el-tag>
+        </el-descriptions-item>
+        <el-descriptions-item label="瀹㈡埛鍚嶇О">{{ detail.customerName }}</el-descriptions-item>
+        <el-descriptions-item label="璁㈠崟鍙�">{{ detail.salesContractNo }}</el-descriptions-item>
+        <el-descriptions-item label="涓氬姟鍛�">{{ detail.salesman }}</el-descriptions-item>
+        <el-descriptions-item label="鍏宠仈鎵瑰彿">{{ detail.shippingNo }}</el-descriptions-item>
+        <!-- <el-descriptions-item label="椤圭洰鍚嶇О">{{ detail.projectName }}</el-descriptions-item> -->
+        <el-descriptions-item label="鍒跺崟浜�">{{ detail.maker }}</el-descriptions-item>
+        <el-descriptions-item label="鍒跺崟鏃堕棿">{{ detail.makeTime }}</el-descriptions-item>
+        <el-descriptions-item label="閫�璐у師鍥�">{{ detail.returnReason }}</el-descriptions-item>
+        <el-descriptions-item label="閫�娆炬�婚">{{ detail.refundAmount }}</el-descriptions-item>
+      </el-descriptions>
+
+      <div style="padding-top: 20px">
+        <span class="descriptions">浜у搧鍒楄〃</span>
+        <PIMTable :isShowPagination="false" rowKey="id" :column="tableColumn" :tableData="tableData">
+        </PIMTable>
+      </div>
+    </div>
+    <template #footer>
+      <div class="dialog-footer">
+        <el-button @click="closeDia">鍏抽棴</el-button>
+      </div>
+    </template>
+  </el-dialog>
+</template>
+
+<script setup>
+import { ref } from "vue";
+import { returnManagementGetById, returnManagementGetByShippingId } from "@/api/salesManagement/returnOrder.js";
+
+const dialogVisible = ref(false);
+const loading = ref(false);
+const detail = ref({});
+const tableData = ref([]);
+const availableProducts = ref([]);
+
+const sameKey = (a, b) => a != null && b != null && String(a) === String(b);
+
+/** 涓� formDia 涓�鑷达細涓や唤鍒楄〃鎸� id 鍚堝苟锛岄伩鍏嶅彧鍙� productDtoData 鏃剁己鍑哄簱鍗曞彿/鎵规/鏁伴噺 */
+const mergeShippingProductLists = (data) => {
+  const lists = [data?.shippingProductVoList, data?.productDtoData].filter(Array.isArray);
+  if (!lists.length) return [];
+  const map = new Map();
+  for (const list of lists) {
+    for (const p of list) {
+      if (p == null) continue;
+      const key = p.id != null ? String(p.id) : null;
+      if (!key) continue;
+      const prev = map.get(key);
+      map.set(key, prev ? { ...prev, ...p } : { ...p });
+    }
+  }
+  return Array.from(map.values());
+};
+
+const pickShippingLine = (normalized) => {
+  const pid = normalized?.returnSaleLedgerProductId ?? normalized?.id;
+  const sid = normalized?.stockOutRecordId ?? normalized?.shippingProductId;
+  const direct = availableProducts.value.find(
+    (p) =>
+      sameKey(p?.id, pid) ||
+      sameKey(p?.stockOutRecordId, pid) ||
+      sameKey(p?.id, sid) ||
+      sameKey(p?.stockOutRecordId, sid)
+  );
+  if (direct) return direct;
+  const pmid = normalized?.productModelId;
+  if (pmid == null || pmid === "") return undefined;
+  const candidates = availableProducts.value.filter((p) => sameKey(p?.productModelId, pmid));
+  if (!candidates.length) return undefined;
+  if (candidates.length === 1) return candidates[0];
+  const spec = String(normalized?.specificationModel ?? normalized?.model ?? "");
+  if (spec) {
+    const hit = candidates.find((p) => {
+      const ps = String(p?.specificationModel ?? p?.model ?? "");
+      return ps && ps === spec;
+    });
+    if (hit) return hit;
+  }
+  return candidates[0];
+};
+
+const isEmptyText = (v) => v === "" || v == null || v === undefined;
+
+const firstFiniteNumber = (...vals) => {
+  for (const v of vals) {
+    if (v === "" || v == null || v === undefined) continue;
+    const n = Number(v);
+    if (Number.isFinite(n)) return n;
+  }
+  return undefined;
+};
+
+const firstNonEmptyText = (...vals) => {
+  const hit = vals.find((v) => !isEmptyText(v));
+  return hit === undefined ? "" : hit;
+};
+
+/** 璇︽儏琛ㄧ敤 productName / model锛涘悎骞舵椂鍕胯绌轰覆鐩栨帀鍑哄簱琛屽瓧娈� */
+const mergeDetailProductRow = (product, normalized) => {
+  const row = { ...product, ...normalized };
+  row.outboundBatches = firstNonEmptyText(
+    row.outboundBatches,
+    product?.outboundBatches,
+    product?.shippingNo,
+    product?.outboundNo,
+    normalized?.outboundBatches,
+    normalized?.outboundNo,
+    normalized?.shippingNo
+  );
+  row.batchNo = firstNonEmptyText(
+    row.batchNo,
+    product?.batchNo,
+    product?.batchNumber,
+    product?.lotNo,
+    product?.batchCode,
+    product?.shippingBatchNo,
+    normalized?.batchNo,
+    normalized?.batchNumber,
+    normalized?.lotNo,
+    normalized?.shippingBatchNo
+  );
+  const stock = firstFiniteNumber(
+    row.stockOutNum,
+    product?.stockOutNum,
+    product?.totalQuantity,
+    product?.shippingQuantity,
+    product?.deliveryQuantity,
+    product?.quantity,
+    product?.outQuantity,
+    normalized?.stockOutNum,
+    normalized?.totalQuantity,
+    normalized?.shippingQuantity,
+    normalized?.deliveryQuantity
+  );
+  if (stock !== undefined) row.stockOutNum = stock;
+  const un = firstFiniteNumber(
+    row.unQuantity,
+    product?.unQuantity,
+    product?.remainingQuantity,
+    product?.noReturnQuantity,
+    product?.canReturnQuantity,
+    product?.availableReturnNum,
+    normalized?.unQuantity,
+    normalized?.remainingQuantity,
+    normalized?.noReturnQuantity,
+    normalized?.canReturnQuantity
+  );
+  if (un !== undefined) row.unQuantity = un;
+  else {
+    const s = Number(row.stockOutNum);
+    const ret = Number(row.totalReturnNum ?? 0);
+    if (Number.isFinite(s) && s >= 0 && Number.isFinite(ret) && ret >= 0) {
+      row.unQuantity = Math.max(0, s - ret);
+    }
+  }
+  const returned = firstFiniteNumber(
+    row.totalReturnNum,
+    product?.totalReturnNum,
+    product?.totalReturnedNum,
+    normalized?.totalReturnNum,
+    normalized?.totalReturnedNum
+  );
+  if (returned !== undefined) row.totalReturnNum = returned;
+  else if (isEmptyText(row.totalReturnNum)) row.totalReturnNum = 0;
+  if (isEmptyText(row.unit)) {
+    row.unit = firstNonEmptyText(product?.unit, normalized?.unit);
+  }
+  row.productName = firstNonEmptyText(
+    row.productName,
+    normalized?.productName,
+    normalized?.productCategory,
+    product?.productName,
+    product?.productCategory
+  );
+  row.model = firstNonEmptyText(
+    row.model,
+    normalized?.model,
+    normalized?.specificationModel,
+    product?.model,
+    product?.specificationModel
+  );
+  return row;
+};
+
+const normalizeDetailRow = (raw) => {
+  const ledgerId =
+    raw?.returnSaleLedgerProductId ??
+    raw?.saleLedgerProductId ??
+    raw?.stockOutRecordId ??
+    raw?.shippingProductId;
+  const productId = ledgerId ?? raw?.id;
+  const num = Number(raw?.num ?? raw?.returnQuantity ?? 0);
+  return {
+    ...raw,
+    id: productId,
+    returnSaleLedgerProductId: productId,
+    productModelId: raw?.productModelId,
+    stockOutRecordId: raw?.stockOutRecordId,
+    shippingProductId: raw?.shippingProductId,
+    productName: raw?.productName ?? raw?.productCategory ?? raw?.productTypeName ?? "",
+    model: raw?.model ?? raw?.specificationModel ?? raw?.specModel ?? "",
+    outboundBatches: raw?.outboundBatches ?? raw?.outboundNo ?? raw?.shippingNo,
+    batchNo:
+      raw?.batchNo ??
+      raw?.batchNumber ??
+      raw?.lotNo ??
+      raw?.batchCode ??
+      raw?.shippingBatchNo,
+    stockOutNum:
+      raw?.stockOutNum ??
+      raw?.totalQuantity ??
+      raw?.shippingQuantity ??
+      raw?.deliveryQuantity ??
+      raw?.quantity,
+    totalReturnNum: raw?.totalReturnNum ?? raw?.totalReturnedNum,
+    unQuantity:
+      raw?.unQuantity ??
+      raw?.remainingQuantity ??
+      raw?.noReturnQuantity ??
+      raw?.canReturnQuantity,
+    returnQuantity: Number.isFinite(num) ? num : 0,
+    price: Number(raw?.taxInclusiveUnitPrice ?? raw?.price ?? 0),
+    amount: Number(raw?.amount ?? 0).toFixed(2),
+    isQuality: raw?.isQuality ?? 2,
+    remark: raw?.remark ?? "",
+  };
+};
+
+const tableColumn = [
+  {align: "center", label: "鍑哄簱鍗曞彿", prop: "outboundBatches"},
+  {align: "center", label: "鎵规鍙�", prop: "batchNo"},
+  {align: "center", label: "浜у搧澶х被", prop: "productName"},
+  {align: "center", label: "瑙勬牸鍨嬪彿", prop: "model"},
+  {align: "center", label: "鍗曚綅", prop: "unit", width: 80},
+  {align: "center", label: "鎬绘暟閲�", prop: "stockOutNum", width: 120},
+  {align: "center", label: "宸查��璐ф暟閲�", prop: "totalReturnNum", width: 120},
+  {align: "center", label: "鏈��璐ф暟閲�", prop: "unQuantity", width: 120},
+  {align: "center", label: "閫�璐ф暟閲�", prop: "returnQuantity", width: 120},
+  {align: "center", label: "閫�璐т骇鍝佸崟浠�", prop: "price", width: 120},
+  {align: "center", label: "閫�璐т骇鍝侀噾棰�", prop: "amount", width: 120},
+  {align: "center", label: "鏄惁鏈夎川閲忛棶棰�", prop: "isQuality", width: 140, formatData: (v) => ({ "1": "鏄�", "2": "鍚�" }[String(v)] ?? v)},
+  {align: "center", label: "澶囨敞", prop: "remark", width: 150},
+];
+
+const getStatusType = (status) => {
+  const statusMap = {
+    0: "warning",
+    1: "success"
+  };
+  return statusMap[status] || "info";
+};
+
+const getStatusText = (status) => {
+  const statusMap = {
+    0: "寰呭鐞�",
+    1: "宸插鐞�"
+  };
+  return statusMap[status] || "鏈煡";
+};
+
+const openDialog = async (row) => {
+  if (!row?.id) return;
+  dialogVisible.value = true;
+  loading.value = true;
+  try {
+    const res = await returnManagementGetById({ returnManagementId: row.id });
+    detail.value = res?.data ?? res ?? {};
+    
+    if (detail.value.shippingId) {
+      const productRes = await returnManagementGetByShippingId({ shippingId: detail.value.shippingId });
+      if (productRes.code === 200) {
+        availableProducts.value = mergeShippingProductLists(productRes.data);
+      }
+    }
+
+    const list =
+      detail.value?.returnSaleProducts ||
+      detail.value?.returnSaleProductList ||
+      detail.value?.returnSaleProductDtoData ||
+      [];
+
+    tableData.value = Array.isArray(list)
+      ? list.map((raw) => {
+          const normalized = normalizeDetailRow(raw);
+          const product = pickShippingLine(normalized);
+          return product ? mergeDetailProductRow(product, normalized) : normalized;
+        })
+      : [];
+
+    const headerShipNo = detail.value?.shippingNo;
+    if (headerShipNo && Array.isArray(tableData.value) && tableData.value.length) {
+      tableData.value = tableData.value.map((r) =>
+        isEmptyText(r.outboundBatches) ? { ...r, outboundBatches: headerShipNo } : r
+      );
+    }
+  } catch (e) {
+    console.error("Failed to load detail", e);
+  } finally {
+    loading.value = false;
+  }
+};
+
+const closeDia = () => {
+  dialogVisible.value = false;
+  detail.value = {};
+  tableData.value = [];
+  availableProducts.value = [];
+};
+
+defineExpose({ openDialog });
+</script>
+
+<style scoped lang="scss">
+.descriptions {
+  margin-bottom: 20px;
+  display: inline-block;
+  font-size: 1rem;
+  font-weight: 600;
+  padding-left: 12px;
+  position: relative;
+}
+.descriptions::before {
+  content: "";
+  position: absolute;
+  left: 0;
+  top: 50%;
+  transform: translateY(-50%);
+  width: 4px;
+  height: 1rem;
+  background-color: #002FA7;
+  border-radius: 2px;
+}
+</style>

--
Gitblit v1.9.3