From 1ad589405bf2b26a8e896fa6ac5361c316bb9026 Mon Sep 17 00:00:00 2001
From: buhuazhen <hua100783@gmail.com>
Date: 星期四, 12 三月 2026 09:54:49 +0800
Subject: [PATCH] fix(客户服务): 修复产品选择对话框行标识不一致问题

---
 src/views/customerService/feedbackRegistration/components/formDia.vue             |   55 ++++++++++-------
 src/views/customerService/feedbackRegistration/components/ProductSelectDialog.vue |  118 ++++++++++++++++++++++++--------------
 2 files changed, 106 insertions(+), 67 deletions(-)

diff --git a/src/views/customerService/feedbackRegistration/components/ProductSelectDialog.vue b/src/views/customerService/feedbackRegistration/components/ProductSelectDialog.vue
index 4df22bc..37e21ef 100644
--- a/src/views/customerService/feedbackRegistration/components/ProductSelectDialog.vue
+++ b/src/views/customerService/feedbackRegistration/components/ProductSelectDialog.vue
@@ -16,8 +16,8 @@
     </el-form>
 
     <!-- 鍒楄〃 -->
-    <el-table ref="tableRef" v-loading="loading" :data="tableData" height="420" highlight-current-row row-key="id"
-      @selection-change="handleSelectionChange" @select="handleSelect">
+    <el-table ref="tableRef" v-loading="loading" :data="tableData" height="420" highlight-current-row :row-key="getRowKey"
+      @selection-change="handleSelectionChange">
       <el-table-column type="selection" width="55" />
       <el-table-column type="index" label="搴忓彿" width="60" />
       <template v-for="column in visibleColumns" :key="column.prop">
@@ -79,8 +79,8 @@
 });
 
 const query = reactive({
-  productName: "",
-  model: "",
+  productCategory: "",
+  unit: "",
 });
 
 const page = reactive({
@@ -92,6 +92,7 @@
 const tableData = ref([]);
 const total = ref(0);
 const multipleSelection = ref([]);
+const selectedRowMap = ref(new Map());
 const tableRef = ref();
 
 const columnsDialogVisible = ref(false);
@@ -106,6 +107,29 @@
 const visibleColumns = computed(() => {
   return allColumns.value.filter(c => selectedColumns.value.includes(c.prop));
 });
+
+const getRowKey = (row) => {
+  return row?.id ?? row?.productModelId ?? `${row?.productCategory || ""}-${row?.specificationModel || row?.model || ""}-${row?.unit || ""}`;
+};
+
+const syncMultipleSelection = () => {
+  multipleSelection.value = Array.from(selectedRowMap.value.values());
+};
+
+const initSelectionFromProps = () => {
+  const selectedIdSet = new Set((props.selectedIds || []).map((id) => String(id)));
+  selectedRowMap.value = new Map();
+  if (!selectedIdSet.size) {
+    syncMultipleSelection();
+    return;
+  }
+  (props.products || []).forEach((row) => {
+    if (selectedIdSet.has(String(row?.id))) {
+      selectedRowMap.value.set(getRowKey(row), row);
+    }
+  });
+  syncMultipleSelection();
+};
 
 const resetColumns = () => {
   selectedColumns.value = allColumns.value.filter(c => c.selected).map(c => c.prop);
@@ -124,39 +148,33 @@
 }
 
 const handleSelectionChange = (val) => {
+  const currentPageKeys = new Set(tableData.value.map((item) => getRowKey(item)));
+  currentPageKeys.forEach((key) => selectedRowMap.value.delete(key));
+
   if (props.single && val.length > 1) {
-    // 濡傛灉闄愬埗涓哄崟涓�夋嫨锛屽彧淇濈暀鏈�鍚庝竴涓�変腑鐨�
     const lastSelected = val[val.length - 1];
-    multipleSelection.value = [lastSelected];
-    // 娓呯┖琛ㄦ牸閫変腑鐘舵�侊紝鐒跺悗閲嶆柊閫変腑鏈�鍚庝竴涓�
+    selectedRowMap.value = new Map();
+    if (lastSelected) {
+      selectedRowMap.value.set(getRowKey(lastSelected), lastSelected);
+    }
+    syncMultipleSelection();
     nextTick(() => {
       if (tableRef.value) {
         tableRef.value.clearSelection();
         tableRef.value.toggleRowSelection(lastSelected, true);
       }
     });
-  } else {
-    multipleSelection.value = val;
-  }
-}
-
-// 澶勭悊鍗曚釜閫夋嫨
-const handleSelect = (selection, row) => {
-  if (props.single) {
-    // 濡傛灉闄愬埗涓哄崟涓紝娓呯┖鍏朵粬閫夋嫨锛屽彧淇濈暀褰撳墠琛�
-    if (selection.includes(row)) {
-      // 閫変腑褰撳墠琛屾椂锛屾竻绌哄叾浠栭�変腑
-      multipleSelection.value = [row];
-      nextTick(() => {
-        if (tableRef.value) {
-          tableData.value.forEach((item) => {
-            if (item.id !== row.id) {
-              tableRef.value.toggleRowSelection(item, false);
-            }
-          });
-        }
-      });
+  } else if (props.single) {
+    selectedRowMap.value = new Map();
+    if (val[0]) {
+      selectedRowMap.value.set(getRowKey(val[0]), val[0]);
     }
+    syncMultipleSelection();
+  } else {
+    val.forEach((row) => {
+      selectedRowMap.value.set(getRowKey(row), row);
+    });
+    syncMultipleSelection();
   }
 }
 
@@ -166,8 +184,8 @@
 }
 
 function onReset() {
-  query.productName = "";
-  query.model = "";
+  query.productCategory = "";
+  query.unit = "";
   page.pageNum = 1;
   loadData();
 }
@@ -192,32 +210,29 @@
 async function loadData() {
   loading.value = true;
   try {
-    multipleSelection.value = []; // 缈婚〉/鎼滅储鍚庢竻绌洪�夋嫨鏇寸鍚堥鏈�
-
     let filtered = props.products || [];
-    // 鏈湴鎼滅储杩囨护
-    if (query.productName) {
-      filtered = filtered.filter(item => item.productName && item.productName.includes(query.productName));
+    if (query.productCategory) {
+      filtered = filtered.filter(item => item.productCategory && item.productCategory.includes(query.productCategory));
     }
-    if (query.model) {
-      filtered = filtered.filter(item => item.model && item.model.includes(query.model));
+    if (query.unit) {
+      filtered = filtered.filter(item => item.unit && item.unit.includes(query.unit));
     }
 
     total.value = filtered.length;
-    // 鍓嶇鍒嗛〉
     const start = (page.pageNum - 1) * page.pageSize;
     const end = start + page.pageSize;
     tableData.value = filtered.slice(start, end);
 
-    // 鑷姩鍥炴樉閫変腑鐘舵��
     nextTick(() => {
       if (tableRef.value) {
+        tableRef.value.clearSelection();
         tableData.value.forEach(row => {
-          if (props.selectedIds && props.selectedIds.includes(row.id)) {
+          if (selectedRowMap.value.has(getRowKey(row))) {
             tableRef.value.toggleRowSelection(row, true);
           }
         });
       }
+      syncMultipleSelection();
     });
   } finally {
     loading.value = false;
@@ -227,16 +242,31 @@
 // 鐩戝惉寮圭獥鎵撳紑锛岄噸缃�夋嫨
 watch(() => props.modelValue, (visible) => {
   if (visible) {
-    // 姣忔鎵撳紑鏃堕噸鏂板垵濮嬪寲閫変腑鐘舵�侊紙multipleSelection 浼氶�氳繃 loadData 涓殑鍥炴樉閫昏緫鑷姩鏇存柊锛屼絾鍒濆闇�缃┖閬垮厤閲嶅锛�
-    multipleSelection.value = [];
+    initSelectionFromProps();
     page.pageNum = 1;
     loadData();
   }
 });
 
-// 鐩戝惉鏁版嵁婧愬彉鍖�
 watch(() => props.products, () => {
-  loadData();
+  const latestMap = new Map();
+  const currentKeys = new Set(selectedRowMap.value.keys());
+  (props.products || []).forEach((row) => {
+    const key = getRowKey(row);
+    if (currentKeys.has(key)) {
+      latestMap.set(key, row);
+    }
+  });
+  selectedRowMap.value.forEach((row, key) => {
+    if (!latestMap.has(key)) {
+      latestMap.set(key, row);
+    }
+  });
+  selectedRowMap.value = latestMap;
+  syncMultipleSelection();
+  if (props.modelValue) {
+    loadData();
+  }
 }, { deep: true });
 
 onMounted(() => {
diff --git a/src/views/customerService/feedbackRegistration/components/formDia.vue b/src/views/customerService/feedbackRegistration/components/formDia.vue
index 2af71da..71cd167 100644
--- a/src/views/customerService/feedbackRegistration/components/formDia.vue
+++ b/src/views/customerService/feedbackRegistration/components/formDia.vue
@@ -185,6 +185,31 @@
 const serviceTypeOptions = computed(() => post_sale_waiting_list?.value || []);
 const urgencyOptions = computed(() => degree_of_urgency?.value || []);
 
+const getProductRowId = (row) => {
+  return row?.id ?? row?.productModelId ?? row?.modelId ?? `${row?.productCategory || row?.productName || ""}-${row?.specificationModel || row?.model || ""}-${row?.unit || ""}`
+}
+
+const normalizeProductRow = (row) => {
+  return {
+    ...row,
+    id: getProductRowId(row),
+    productCategory: row?.productCategory ?? row?.productName ?? '',
+    specificationModel: row?.specificationModel ?? row?.model ?? '',
+    unit: row?.unit ?? '',
+    approveStatus: row?.approveStatus ?? null,
+    shippingStatus: row?.shippingStatus ?? '',
+    expressCompany: row?.expressCompany ?? '',
+    expressNumber: row?.expressNumber ?? '',
+    shippingCarNumber: row?.shippingCarNumber ?? '',
+    shippingDate: row?.shippingDate ?? '',
+    quantity: row?.quantity ?? 0,
+    taxRate: row?.taxRate ?? 0,
+    taxInclusiveUnitPrice: row?.taxInclusiveUnitPrice ?? 0,
+    taxInclusiveTotalPrice: row?.taxInclusiveTotalPrice ?? 0,
+    taxExclusiveTotalPrice: row?.taxExclusiveTotalPrice ?? 0,
+  }
+}
+
 const tableColumn = ref([
   { label: "浜у搧澶х被", prop: "productCategory" },
   { label: "瑙勬牸鍨嬪彿", prop: "specificationModel" },
@@ -239,7 +264,7 @@
         name: "鍒犻櫎",
         type: "text",
         clickFun: (row) => {
-          tableData.value = tableData.value.filter(i => i.id !== row.id)
+          tableData.value = tableData.value.filter(i => getProductRowId(i) !== getProductRowId(row))
         },
 
       },
@@ -251,37 +276,21 @@
 const isShowProductSelectDialog = ref(false)
 const handleSelectProducts = (rows) => {
   if (!Array.isArray(rows)) return
-  const existingIds = new Set(tableData.value.map(i => i.id))
+  const existingIds = new Set(tableData.value.map(i => String(getProductRowId(i))))
   const mapped = rows
-    .filter(r => !existingIds.has(r.id))
-    .map(r => ({
-      id: r.id,
-      productCategory: r.productName,
-      specificationModel: r.model,
-      unit: r.unit || '',
-      approveStatus: null,
-      shippingStatus: '',
-      expressCompany: '',
-      expressNumber: '',
-      shippingCarNumber: '',
-      shippingDate: '',
-      quantity: 0,
-      taxRate: 0,
-      taxInclusiveUnitPrice: 0,
-      taxInclusiveTotalPrice: 0,
-      taxExclusiveTotalPrice: 0,
-    }))
+    .map(normalizeProductRow)
+    .filter(r => !existingIds.has(String(getProductRowId(r))))
   tableData.value = tableData.value.concat(mapped)
 }
 const currentSelectedProductIds = computed(() => {
-  return tableData.value.map(item => item.id)
+  return tableData.value.map(item => getProductRowId(item)).filter(item => item !== undefined && item !== null && item !== '')
 })
 
 const associatedSalesOrderNumberChange = () => {
   const opt = associatedSalesOrderNumberOptions.value.find(
     (item) => item.value === form.value.salesContractNo
   )
-  tableData.value = opt?.productData || []
+  tableData.value = (opt?.productData || []).map(normalizeProductRow)
   form.value.salesLedgerId = opt?.id || null
 }
 
@@ -291,7 +300,7 @@
   const opt = associatedSalesOrderNumberOptions.value.find(
     (item) => item.value === form.value.salesContractNo
   )
-  return opt?.productData || []
+  return (opt?.productData || []).map(normalizeProductRow)
 })
 
 const customerNameChange = (val) => {

--
Gitblit v1.9.3