From 9ea5ff67655241271bdf04bb50ca3a8d60c4e22a Mon Sep 17 00:00:00 2001
From: yuan <123@>
Date: 星期二, 11 八月 2026 15:07:02 +0800
Subject: [PATCH] fix: 用河南鹤壁代码覆盖山西长治

---
 src/views/qualityManagement/metricBinding/index.vue | 1095 ++++++++++++++++++++++++++++++--------------------------
 1 files changed, 584 insertions(+), 511 deletions(-)

diff --git a/src/views/qualityManagement/metricBinding/index.vue b/src/views/qualityManagement/metricBinding/index.vue
index 6e7a881..ba989ea 100644
--- a/src/views/qualityManagement/metricBinding/index.vue
+++ b/src/views/qualityManagement/metricBinding/index.vue
@@ -1,167 +1,168 @@
 <template>
   <div class="app-container metric-binding">
-    <el-row :gutter="16"
-            class="metric-binding-row">
+    <el-row :gutter="16" class="metric-binding-row">
       <!-- 宸︿晶锛氭娴嬫爣鍑嗗垪琛� -->
-      <el-col :xs="24"
-              :sm="24"
-              :md="12"
-              :lg="14"
-              :xl="14"
-              class="left-col">
+      <el-col :xs="24" :sm="24" :md="12" :lg="14" :xl="14" class="left-col">
         <div class="panel left-panel">
-          <PIMTable rowKey="id"
-                    :column="standardColumns"
-                    :tableData="standardTableData"
-                    :page="page"
-                    :isSelection="false"
-                    :rowClassName="rowClassNameCenter"
-                    :tableLoading="tableLoading"
-                    :rowClick="handleTableRowClick"
-                    @pagination="handlePagination"
-                    :total="page.total">
-            <template #standardNoCell="{ row }">
-              <span class="clickable-link"
-                    @click="handleStandardRowClick(row)">
-                {{ row.standardNo }}
-              </span>
-            </template>
-            <!-- 琛ㄥご鎼滅储 -->
-            <template #standardNoHeader>
-              <el-input v-model="searchForm.standardNo"
-                        placeholder="鏍囧噯缂栧彿"
-                        clearable
-                        size="small"
-                        @change="handleQuery"
-                        @clear="handleQuery" />
-            </template>
-            <template #standardNameHeader>
-              <el-input v-model="searchForm.standardName"
-                        placeholder="鏍囧噯鍚嶇О"
-                        clearable
-                        size="small"
-                        @change="handleQuery"
-                        @clear="handleQuery" />
-            </template>
-            <template #inspectTypeHeader>
-              <el-select v-model="searchForm.inspectType"
-                         placeholder="绫诲埆"
-                         clearable
-                         size="small"
-                         style="width: 120px"
-                         @change="handleQuery"
-                         @clear="handleQuery">
-                <el-option label="鍘熸潗鏂欐楠�"
-                           value="0" />
-                <el-option label="杩囩▼妫�楠�"
-                           value="1" />
-                <el-option label="鍑哄巶妫�楠�"
-                           value="2" />
-              </el-select>
-            </template>
-            <template #stateHeader>
-              <el-select v-model="searchForm.state"
-                         placeholder="鐘舵��"
-                         clearable
-                         size="small"
-                         style="width: 110px"
-                         @change="handleQuery"
-                         @clear="handleQuery">
-                <el-option label="鑽夌"
-                           value="0" />
-                <el-option label="閫氳繃"
-                           value="1" />
-                <el-option label="鎾ら攢"
-                           value="2" />
-              </el-select>
-            </template>
-          </PIMTable>
+      <PIMTable
+        rowKey="id"
+        :column="standardColumns"
+        :tableData="standardTableData"
+        :page="page"
+        :isSelection="false"
+        :rowClassName="rowClassNameCenter"
+        :tableLoading="tableLoading"
+        :rowClick="handleTableRowClick"
+        @pagination="handlePagination"
+        :total="page.total"
+      >
+        <template #standardNoCell="{ row }">
+          <span class="clickable-link" @click="handleStandardRowClick(row)">
+            {{ row.standardNo }}
+          </span>
+        </template>
+
+        <!-- 琛ㄥご鎼滅储 -->
+        <template #standardNoHeader>
+          <el-input
+            v-model="searchForm.standardNo"
+            placeholder="鏍囧噯缂栧彿"
+            clearable
+            size="small"
+            @change="handleQuery"
+            @clear="handleQuery"
+          />
+        </template>
+        <template #standardNameHeader>
+          <el-input
+            v-model="searchForm.standardName"
+            placeholder="鏍囧噯鍚嶇О"
+            clearable
+            size="small"
+            @change="handleQuery"
+            @clear="handleQuery"
+          />
+        </template>
+        <template #inspectTypeHeader>
+          <el-select
+            v-model="searchForm.inspectType"
+            placeholder="绫诲埆"
+            clearable
+            size="small"
+            style="width: 120px"
+            @change="handleQuery"
+            @clear="handleQuery"
+          >
+            <el-option label="鍘熸潗鏂欐楠�" value="0" />
+            <el-option label="杩囩▼妫�楠�" value="1" />
+            <el-option label="鍑哄巶妫�楠�" value="2" />
+          </el-select>
+        </template>
+        <template #stateHeader>
+          <el-select
+            v-model="searchForm.state"
+            placeholder="鐘舵��"
+            clearable
+            size="small"
+            style="width: 110px"
+            @change="handleQuery"
+            @clear="handleQuery"
+          >
+            <el-option label="鑽夌" value="0" />
+            <el-option label="閫氳繃" value="1" />
+            <el-option label="鎾ら攢" value="2" />
+          </el-select>
+        </template>
+      </PIMTable>
         </div>
       </el-col>
+
       <!-- 鍙充晶锛氱粦瀹氬垪琛� -->
-      <el-col :xs="24"
-              :sm="24"
-              :md="12"
-              :lg="10"
-              :xl="10"
-              class="right-col">
+      <el-col :xs="24" :sm="24" :md="12" :lg="10" :xl="10" class="right-col">
         <div class="panel right-panel">
-          <div class="right-header">
-            <div class="title">缁戝畾鍏崇郴</div>
-            <div class="desc"
-                 v-if="currentStandard">
-              褰撳墠妫�娴嬫爣鍑嗙紪鍙凤細<span class="link-text">{{ currentStandard.standardNo }}</span>
-            </div>
-            <div class="desc"
-                 v-else>璇烽�夋嫨宸︿晶妫�娴嬫爣鍑�</div>
-          </div>
-          <div class="right-toolbar">
-            <el-button type="primary"
-                       :disabled="!currentStandard"
-                       @click="openBindingDialog">娣诲姞缁戝畾</el-button>
-            <el-button type="danger"
-                       plain
-                       :disabled="!currentStandard"
-                       @click="handleBatchUnbind">鍒犻櫎</el-button>
-          </div>
-          <el-table v-loading="bindingLoading"
-                    :data="bindingTableData"
-                    border
-                    :row-class-name="() => 'row-center'"
-                    class="center-table"
-                    style="width: 100%"
-                    height="calc(100vh - 220px)"
-                    @selection-change="handleBindingSelectionChange">
-            <el-table-column type="selection"
-                             width="48"
-                             align="center" />
-            <el-table-column type="index"
-                             label="搴忓彿"
-                             width="60"
-                             align="center" />
-            <el-table-column prop="productName"
-                             label="浜у搧鍚嶇О"
-                             min-width="140" />
-            <el-table-column label="鎿嶄綔"
-                             width="120"
-                             fixed="right"
-                             align="center">
-              <template #default="{ row }">
-                <el-button link
-                           type="danger"
-                           size="small"
-                           @click="handleUnbind(row)">鍒犻櫎</el-button>
-              </template>
-            </el-table-column>
-          </el-table>
+      <div class="right-header">
+        <div class="title">缁戝畾鍏崇郴</div>
+        <div class="desc" v-if="currentStandard">
+          褰撳墠妫�娴嬫爣鍑嗙紪鍙凤細<span class="link-text">{{ currentStandard.standardNo }}</span>
+        </div>
+        <div class="desc" v-else>璇烽�夋嫨宸︿晶妫�娴嬫爣鍑�</div>
+      </div>
+
+      <div class="right-toolbar">
+        <el-button type="primary" :disabled="!currentStandard" @click="openBindingDialog">娣诲姞缁戝畾</el-button>
+        <el-button type="danger" plain :disabled="!currentStandard" @click="handleBatchUnbind">鍒犻櫎</el-button>
+      </div>
+
+      <el-table
+        v-loading="bindingLoading"
+        :data="bindingTableData"
+        border
+        :row-class-name="() => 'row-center'"
+        class="center-table"
+        style="width: 100%"
+        height="calc(100vh - 220px)"
+        @selection-change="handleBindingSelectionChange"
+      >
+        <el-table-column type="selection" width="48" align="center" />
+        <el-table-column type="index" label="搴忓彿" width="60" align="center" />
+        <el-table-column prop="productName" label="浜у搧鍚嶇О" min-width="140" />
+        <el-table-column label="鎿嶄綔" width="120" fixed="right" align="center">
+          <template #default="{ row }">
+            <el-button link type="danger" size="small" @click="handleUnbind(row)">鍒犻櫎</el-button>
+          </template>
+        </el-table-column>
+      </el-table>
         </div>
       </el-col>
     </el-row>
+
     <!-- 娣诲姞缁戝畾寮规 -->
-    <el-dialog v-model="bindingDialogVisible"
-               title="娣诲姞缁戝畾"
-               width="520px"
-               @close="closeBindingDialog">
-      <el-form label-width="100px">
-        <el-form-item label="浜у搧">
-          <PIMTreeSelect v-model="selectedProductIds"
-                         multiple
-                         filterable
-                         collapse-tags
-                         collapse-tags-tooltip
-                         placeholder="璇烽�夋嫨浜у搧锛堝彲澶氶�夛級"
-                         clearable
-                         check-strictly
-                         :data="productOptions"
-                         :render-after-expand="false"
-                         style="width: 100%" />
-        </el-form-item>
-      </el-form>
+    <el-dialog
+      v-model="bindingDialogVisible"
+      title="娣诲姞缁戝畾"
+      width="640px"
+      @close="closeBindingDialog"
+    >
+      <div class="binding-dialog">
+        <el-input
+          v-model="productSearchKeyword"
+          placeholder="鎼滅储浜у搧"
+          clearable
+          prefix-icon="Search"
+          class="binding-search"
+        />
+        <el-tree
+          ref="productTreeRef"
+          :key="productTreeKey"
+          v-loading="productTreeLoading"
+          :data="productTreeData"
+          show-checkbox
+          check-strictly
+          node-key="id"
+          :props="{ label: 'label', children: 'children', disabled: 'disabled' }"
+          :filter-node-method="filterProductNode"
+          class="product-binding-tree"
+          @check="handleProductTreeCheck"
+        />
+        <div v-if="selectedProductLabels.length" class="selected-products">
+          <div class="selected-title">宸查�夋嫨锛坽{ selectedProductLabels.length }}锛�</div>
+          <div class="selected-tags">
+            <el-tag
+              v-for="item in selectedProductLabels"
+              :key="item.id"
+              closable
+              type="info"
+              @close="removeSelectedProduct(item.id)"
+            >
+              {{ item.label }}
+            </el-tag>
+          </div>
+        </div>
+      </div>
       <template #footer>
         <span class="dialog-footer">
           <el-button @click="closeBindingDialog">鍙栨秷</el-button>
-          <el-button type="primary"
-                     @click="submitBinding">纭畾</el-button>
+          <el-button type="primary" @click="submitBinding">纭畾</el-button>
         </span>
       </template>
     </el-dialog>
@@ -169,404 +170,476 @@
 </template>
 
 <script setup>
-  import { Search } from "@element-plus/icons-vue";
-  import { ref, reactive, toRefs, onMounted, getCurrentInstance } from "vue";
-  import { ElMessageBox } from "element-plus";
-  import PIMTable from "@/components/PIMTable/PIMTable.vue";
-  import PIMTreeSelect from "@/components/PIMTreeSelect/index.vue";
-  import { productTreeList } from "@/api/basicData/product.js";
-  import { qualityTestStandardListPage } from "@/api/qualityManagement/metricMaintenance.js";
-  import { productProcessListPage } from "@/api/basicData/productProcess.js";
-  import {
-    qualityTestStandardBindingList,
-    qualityTestStandardBindingAdd,
-    qualityTestStandardBindingDel,
-  } from "@/api/qualityManagement/qualityTestStandardBinding.js";
+import { ref, reactive, toRefs, computed, watch, nextTick, onMounted, getCurrentInstance } from 'vue'
+import { ElMessageBox } from 'element-plus'
+import PIMTable from '@/components/PIMTable/PIMTable.vue'
+import { productTreeList } from '@/api/basicData/product.js'
+import {
+  qualityTestStandardListPage
+} from '@/api/qualityManagement/metricMaintenance.js'
+import { productProcessListPage } from '@/api/basicData/productProcess.js'
+import {
+  qualityTestStandardBindingList,
+  qualityTestStandardBindingAdd,
+  qualityTestStandardBindingDel
+} from '@/api/qualityManagement/qualityTestStandardBinding.js'
 
-  const { proxy } = getCurrentInstance();
+const { proxy } = getCurrentInstance()
 
-  // 宸︿晶鏍囧噯鍒楄〃锛氭暣琛屽唴瀹瑰眳涓紙閰嶅悎鏍峰紡锛�
-  const rowClassNameCenter = () => "row-center";
+// 宸︿晶鏍囧噯鍒楄〃锛氭暣琛屽唴瀹瑰眳涓紙閰嶅悎鏍峰紡锛�
+const rowClassNameCenter = () => 'row-center'
 
-  const data = reactive({
-    searchForm: {
-      standardNo: "",
-      standardName: "",
-      state: "",
-      inspectType: "",
-    },
-  });
-  const { searchForm } = toRefs(data);
-
-  // 宸︿晶
-  const standardTableData = ref([]);
-  const tableLoading = ref(false);
-  const page = reactive({ current: 1, size: 10, total: 0 });
-
-  // 宸ュ簭涓嬫媺锛堢敤浜庡垪琛ㄥ洖鏄撅級
-  const processOptions = ref([]);
-
-  const getProcessList = async () => {
-    try {
-      const res = await productProcessListPage({ current: 1, size: 1000 });
-      if (res?.code === 200) {
-        const records = res?.data?.records || [];
-        processOptions.value = records.map(item => ({
-          label: item.processName || item.name || item.label,
-          value: item.id || item.processId || item.value,
-        }));
-      }
-    } catch (error) {
-      console.error("鑾峰彇宸ュ簭鍒楄〃澶辫触:", error);
-    }
-  };
-
-  const standardColumns = ref([
-    {
-      label: "鏍囧噯缂栧彿",
-      prop: "standardNo",
-      dataType: "slot",
-      slot: "standardNoCell",
-      minWidth: 160,
-      align: "center",
-      headerSlot: "standardNoHeader",
-    },
-    {
-      label: "鏍囧噯鍚嶇О",
-      prop: "standardName",
-      minWidth: 180,
-      align: "center",
-      headerSlot: "standardNameHeader",
-    },
-    {
-      label: "绫诲埆",
-      prop: "inspectType",
-      headerSlot: "inspectTypeHeader",
-      align: "center",
-      dataType: "tag",
-      formatData: val => {
-        const map = { 0: "鍘熸潗鏂欐楠�", 1: "杩囩▼妫�楠�", 2: "鍑哄巶妫�楠�" };
-        return map[val] || val;
-      },
-    },
-    {
-      label: "宸ュ簭",
-      prop: "processId",
-      align: "center",
-      dataType: "tag",
-      formatData: val => {
-        const target = processOptions.value.find(
-          item => String(item.value) === String(val)
-        );
-        return target?.label || val;
-      },
-    },
-    {
-      label: "澶囨敞",
-      prop: "remark",
-      minWidth: 160,
-      align: "center",
-    },
-    // {
-    //   label: '鐘舵��',
-    //   prop: 'state',
-    //   headerSlot: 'stateHeader',
-    //   dataType: 'tag',
-    //   formatData: (val) => {
-    //     const map = { 0: '鑽夌', 1: '閫氳繃', 2: '鎾ら攢' }
-    //     return map[val] || val
-    //   },
-    //   formatType: (val) => {
-    //     if (val == 1) return 'success'
-    //     if (val == 2) return 'warning'
-    //     return 'info'
-    //   }
-    // }
-  ]);
-
-  const currentStandard = ref(null);
-
-  // 鍙充晶缁戝畾
-  const bindingTableData = ref([]);
-  const bindingLoading = ref(false);
-  const bindingSelectedRows = ref([]);
-  const bindingDialogVisible = ref(false);
-
-  // 浜у搧鏍戯紙鐢ㄤ簬缁戝畾閫夋嫨锛�
-  const productOptions = ref([]);
-  const selectedProductIds = ref([]);
-
-  const getProductOptions = async () => {
-    // 閬垮厤閲嶅璇锋眰
-    if (productOptions.value?.length) return;
-    const res = await productTreeList();
-    productOptions.value = convertIdToValue(Array.isArray(res) ? res : []);
-  };
-
-  function convertIdToValue(data) {
-    return (data || []).map(item => {
-      const { id, children, ...rest } = item;
-      const newItem = {
-        ...rest,
-        value: id,
-      };
-      if (children && children.length > 0) {
-        newItem.children = convertIdToValue(children);
-      }
-      return newItem;
-    });
+const data = reactive({
+  searchForm: {
+    standardNo: '',
+    standardName: '',
+    state: '',
+    inspectType: ''
   }
+})
+const { searchForm } = toRefs(data)
 
-  const handleQuery = () => {
-    page.current = 1;
-    getStandardList();
-  };
+// 宸︿晶
+const standardTableData = ref([])
+const tableLoading = ref(false)
+const page = reactive({ current: 1, size: 10, total: 0 })
 
-  const handlePagination = obj => {
-    page.current = obj.page;
-    page.size = obj.limit;
-    getStandardList();
-  };
+// 宸ュ簭涓嬫媺锛堢敤浜庡垪琛ㄥ洖鏄撅級
+const processOptions = ref([])
 
-  const getStandardList = () => {
-    tableLoading.value = true;
-    qualityTestStandardListPage({
-      ...searchForm.value,
-      current: page.current,
-      size: page.size,
-      state: 1,
+const getProcessList = async () => {
+  try {
+    const res = await productProcessListPage({ current: 1, size: 1000 })
+    if (res?.code === 200) {
+      const records = res?.data?.records || []
+      processOptions.value = records.map((item) => ({
+        label: item.processName || item.name || item.label,
+        value: item.id || item.processId || item.value
+      }))
+    }
+  } catch (error) {
+    console.error('鑾峰彇宸ュ簭鍒楄〃澶辫触:', error)
+  }
+}
+
+const standardColumns = ref([
+  { label: '鏍囧噯缂栧彿', prop: 'standardNo', dataType: 'slot', slot: 'standardNoCell', minWidth: 160, align: 'center', headerSlot: 'standardNoHeader' },
+  { label: '鏍囧噯鍚嶇О', prop: 'standardName', minWidth: 180, align: 'center', headerSlot: 'standardNameHeader' },
+  {
+    label: '绫诲埆',
+    prop: 'inspectType',
+    headerSlot: 'inspectTypeHeader',
+    align: 'center',
+    dataType: 'tag',
+    formatData: (val) => {
+      const map = { 0: '鍘熸潗鏂欐楠�', 1: '杩囩▼妫�楠�', 2: '鍑哄巶妫�楠�' }
+      return map[val] || val
+    }
+  },
+  {
+    label: '宸ュ簭',
+    prop: 'processId',
+    align: 'center',
+    dataType: 'tag',
+    formatData: (val) => {
+      const target = processOptions.value.find(
+        (item) => String(item.value) === String(val)
+      )
+      return target?.label || val
+    }
+  },
+  {
+    label: '澶囨敞',
+    prop: 'remark',
+    minWidth: 160,
+    align: 'center'
+  }
+  // {
+  //   label: '鐘舵��',
+  //   prop: 'state',
+  //   headerSlot: 'stateHeader',
+  //   dataType: 'tag',
+  //   formatData: (val) => {
+  //     const map = { 0: '鑽夌', 1: '閫氳繃', 2: '鎾ら攢' }
+  //     return map[val] || val
+  //   },
+  //   formatType: (val) => {
+  //     if (val == 1) return 'success'
+  //     if (val == 2) return 'warning'
+  //     return 'info'
+  //   }
+  // }
+])
+
+const currentStandard = ref(null)
+
+// 鍙充晶缁戝畾
+const bindingTableData = ref([])
+const bindingLoading = ref(false)
+const bindingSelectedRows = ref([])
+const bindingDialogVisible = ref(false)
+
+// 浜у搧鏍戯紙鐢ㄤ簬缁戝畾閫夋嫨锛�
+const productTreeData = ref([])
+const productTreeLoading = ref(false)
+const productTreeRef = ref(null)
+const productTreeKey = ref(0)
+const productSearchKeyword = ref('')
+const selectedProductIds = ref([])
+
+const markParentNodesDisabled = (nodes) => {
+  return (nodes || []).map((node) => {
+    const children = node.children?.length ? markParentNodesDisabled(node.children) : []
+    return {
+      ...node,
+      children,
+      disabled: children.length > 0
+    }
+  })
+}
+
+const buildProductLabelMap = (nodes, map = {}) => {
+  ;(nodes || []).forEach((node) => {
+    if (node.id != null) {
+      map[node.id] = node.label
+    }
+    if (node.children?.length) {
+      buildProductLabelMap(node.children, map)
+    }
+  })
+  return map
+}
+
+const productLabelMap = computed(() => buildProductLabelMap(productTreeData.value))
+
+const selectedProductLabels = computed(() =>
+  selectedProductIds.value.map((id) => ({
+    id,
+    label: productLabelMap.value[id] || id
+  }))
+)
+
+const filterProductNode = (value, data) => {
+  if (!value) return true
+  return String(data.label || '').includes(value)
+}
+
+watch(productSearchKeyword, (val) => {
+  productTreeRef.value?.filter(val)
+})
+
+const getProductTreeData = async () => {
+  if (productTreeData.value?.length) return
+  productTreeLoading.value = true
+  try {
+    const res = await productTreeList()
+    productTreeData.value = markParentNodesDisabled(Array.isArray(res) ? res : [])
+  } catch (error) {
+    console.error('鑾峰彇浜у搧鏍戝け璐�:', error)
+  } finally {
+    productTreeLoading.value = false
+  }
+}
+
+const handleProductTreeCheck = () => {
+  selectedProductIds.value = productTreeRef.value?.getCheckedKeys(true) || []
+}
+
+const removeSelectedProduct = (id) => {
+  selectedProductIds.value = selectedProductIds.value.filter((item) => item !== id)
+  productTreeRef.value?.setChecked(id, false, false)
+}
+
+const handleQuery = () => {
+  page.current = 1
+  getStandardList()
+}
+
+const handlePagination = (obj) => {
+  page.current = obj.page
+  page.size = obj.limit
+  getStandardList()
+}
+
+const getStandardList = () => {
+  tableLoading.value = true
+  qualityTestStandardListPage({
+    ...searchForm.value,
+    current: page.current,
+    size: page.size,
+    state: 1
+  })
+    .then((res) => {
+      const records = res?.data?.records || []
+      standardTableData.value = records
+      page.total = res?.data?.total || records.length
     })
-      .then(res => {
-        const records = res?.data?.records || [];
-        standardTableData.value = records;
-        page.total = res?.data?.total || records.length;
-      })
-      .finally(() => {
-        tableLoading.value = false;
-      });
-  };
+    .finally(() => {
+      tableLoading.value = false
+    })
+}
 
-  // 琛ㄦ牸琛岀偣鍑伙紝鍔犺浇鍙充晶缁戝畾鍒楄〃
-  const handleTableRowClick = row => {
-    currentStandard.value = row;
-    loadBindingList();
-  };
+// 琛ㄦ牸琛岀偣鍑伙紝鍔犺浇鍙充晶缁戝畾鍒楄〃
+const handleTableRowClick = (row) => {
+  currentStandard.value = row
+  loadBindingList()
+}
 
-  // 宸︿晶琛岀偣鍑伙紝鍔犺浇鍙充晶缁戝畾鍒楄〃锛堜繚鐣欑敤浜庢爣鍑嗙紪鍙峰垪鐨勭偣鍑伙級
-  const handleStandardRowClick = row => {
-    currentStandard.value = row;
-    loadBindingList();
-  };
+// 宸︿晶琛岀偣鍑伙紝鍔犺浇鍙充晶缁戝畾鍒楄〃锛堜繚鐣欑敤浜庢爣鍑嗙紪鍙峰垪鐨勭偣鍑伙級
+const handleStandardRowClick = (row) => {
+  currentStandard.value = row
+  loadBindingList()
+}
 
-  const loadBindingList = () => {
-    if (!currentStandard.value?.id) {
-      bindingTableData.value = [];
-      return;
-    }
-    bindingLoading.value = true;
-    qualityTestStandardBindingList({ testStandardId: currentStandard.value.id })
-      .then(res => {
-        const base = res?.data || [];
-        // 灏嗗綋鍓嶆爣鍑嗙殑宸ュ簭鍜屽娉ㄥ甫鍒扮粦瀹氬垪琛ㄤ腑灞曠ず
-        bindingTableData.value = base.map(item => ({
-          ...item,
-          processId: currentStandard.value?.processId,
-          remark: currentStandard.value?.remark,
-        }));
-      })
-      .finally(() => {
-        bindingLoading.value = false;
-      });
-  };
+const loadBindingList = () => {
+  if (!currentStandard.value?.id) {
+    bindingTableData.value = []
+    return
+  }
+  bindingLoading.value = true
+  qualityTestStandardBindingList({ testStandardId: currentStandard.value.id })
+    .then((res) => {
+      const base = res?.data || []
+      // 灏嗗綋鍓嶆爣鍑嗙殑宸ュ簭鍜屽娉ㄥ甫鍒扮粦瀹氬垪琛ㄤ腑灞曠ず
+      bindingTableData.value = base.map((item) => ({
+        ...item,
+        processId: currentStandard.value?.processId,
+        remark: currentStandard.value?.remark
+      }))
+    })
+    .finally(() => {
+      bindingLoading.value = false
+    })
+}
 
-  const handleBindingSelectionChange = selection => {
-    bindingSelectedRows.value = selection;
-  };
+const handleBindingSelectionChange = (selection) => {
+  bindingSelectedRows.value = selection
+}
 
-  const openBindingDialog = () => {
-    if (!currentStandard.value?.id) return;
-    selectedProductIds.value = [];
-    getProductOptions();
-    bindingDialogVisible.value = true;
-  };
+const openBindingDialog = () => {
+  if (!currentStandard.value?.id) return
+  selectedProductIds.value = []
+  productSearchKeyword.value = ''
+  productTreeKey.value += 1
+  bindingDialogVisible.value = true
+  nextTick(() => {
+    productTreeRef.value?.setCheckedKeys([])
+    productTreeRef.value?.filter('')
+  })
+}
 
-  const closeBindingDialog = () => {
-    bindingDialogVisible.value = false;
-  };
+const closeBindingDialog = () => {
+  bindingDialogVisible.value = false
+  selectedProductIds.value = []
+  productSearchKeyword.value = ''
+  productTreeRef.value?.setCheckedKeys([])
+}
 
-  const submitBinding = async () => {
-    const testStandardId = currentStandard.value?.id;
-    if (!testStandardId) return;
-    const ids = (selectedProductIds.value || []).filter(Boolean);
-    if (!ids.length) {
-      proxy.$message.warning("璇烽�夋嫨浜у搧");
-      return;
-    }
-    const payload = ids.map(pid => ({
-      productId: pid,
-      testStandardId,
-    }));
-    await qualityTestStandardBindingAdd(payload);
-    proxy.$message.success("娣诲姞鎴愬姛");
-    bindingDialogVisible.value = false;
-    loadBindingList();
-  };
+const submitBinding = async () => {
+  const testStandardId = currentStandard.value?.id
+  if (!testStandardId) return
+  const ids = (selectedProductIds.value || []).filter(Boolean)
+  if (!ids.length) {
+    proxy.$message.warning('璇烽�夋嫨浜у搧')
+    return
+  }
+  const payload = ids.map((pid) => ({
+    productId: pid,
+    testStandardId
+  }))
+  await qualityTestStandardBindingAdd(payload)
+  proxy.$message.success('娣诲姞鎴愬姛')
+  bindingDialogVisible.value = false
+  loadBindingList()
+}
 
-  const handleUnbind = async row => {
-    const id = row?.id ?? row?.qualityTestStandardBindingId;
-    if (id == null || id === "") return;
-    try {
-      await ElMessageBox.confirm("纭鍒犻櫎璇ョ粦瀹氾紵", "鎻愮ず", { type: "warning" });
-    } catch {
-      return;
-    }
-    try {
-      await qualityTestStandardBindingDel([id]);
-      proxy.$message.success("鍒犻櫎鎴愬姛");
-      loadBindingList();
-    } catch (err) {
-      console.error("鍒犻櫎缁戝畾澶辫触:", err);
-      proxy.$message?.error(err?.message || "鍒犻櫎澶辫触");
-    }
-  };
+const handleUnbind = async (row) => {
+  const id = row?.id ?? row?.qualityTestStandardBindingId
+  if (id == null || id === '') return
+  try {
+    await ElMessageBox.confirm('纭鍒犻櫎璇ョ粦瀹氾紵', '鎻愮ず', { type: 'warning' })
+  } catch {
+    return
+  }
+  try {
+    await qualityTestStandardBindingDel([id])
+    proxy.$message.success('鍒犻櫎鎴愬姛')
+    loadBindingList()
+  } catch (err) {
+    console.error('鍒犻櫎缁戝畾澶辫触:', err)
+    proxy.$message?.error(err?.message || '鍒犻櫎澶辫触')
+  }
+}
 
-  const handleBatchUnbind = async () => {
-    if (!bindingSelectedRows.value.length) {
-      proxy.$message.warning("璇烽�夋嫨鏁版嵁");
-      return;
-    }
-    const ids = bindingSelectedRows.value
-      .map(i => i?.id ?? i?.qualityTestStandardBindingId)
-      .filter(id => id != null && id !== "");
-    if (!ids.length) {
-      proxy.$message.warning("閫変腑鏁版嵁缂哄皯鏈夋晥 id");
-      return;
-    }
-    try {
-      await ElMessageBox.confirm(
-        "閫変腑鐨勫唴瀹瑰皢琚垹闄わ紝鏄惁纭鍒犻櫎锛�",
-        "鍒犻櫎鎻愮ず",
-        { type: "warning" }
-      );
-    } catch {
-      return;
-    }
-    try {
-      await qualityTestStandardBindingDel(ids);
-      proxy.$message.success("鍒犻櫎鎴愬姛");
-      loadBindingList();
-    } catch (err) {
-      console.error("鎵归噺鍒犻櫎缁戝畾澶辫触:", err);
-      proxy.$message?.error(err?.message || "鍒犻櫎澶辫触");
-    }
-  };
+const handleBatchUnbind = async () => {
+  if (!bindingSelectedRows.value.length) {
+    proxy.$message.warning('璇烽�夋嫨鏁版嵁')
+    return
+  }
+  const ids = bindingSelectedRows.value
+    .map((i) => i?.id ?? i?.qualityTestStandardBindingId)
+    .filter((id) => id != null && id !== '')
+  if (!ids.length) {
+    proxy.$message.warning('閫変腑鏁版嵁缂哄皯鏈夋晥 id')
+    return
+  }
+  try {
+    await ElMessageBox.confirm('閫変腑鐨勫唴瀹瑰皢琚垹闄わ紝鏄惁纭鍒犻櫎锛�', '鍒犻櫎鎻愮ず', { type: 'warning' })
+  } catch {
+    return
+  }
+  try {
+    await qualityTestStandardBindingDel(ids)
+    proxy.$message.success('鍒犻櫎鎴愬姛')
+    loadBindingList()
+  } catch (err) {
+    console.error('鎵归噺鍒犻櫎缁戝畾澶辫触:', err)
+    proxy.$message?.error(err?.message || '鍒犻櫎澶辫触')
+  }
+}
 
-  onMounted(() => {
-    getStandardList();
-    getProcessList();
-  });
+onMounted(() => {
+  getStandardList()
+  getProcessList()
+  getProductTreeData()
+})
 </script>
 
 <style scoped>
-  .metric-binding-row {
-    width: 100%;
-  }
+.metric-binding-row {
+  width: 100%;
+}
 
-  .metric-binding-row .left-col,
-  .metric-binding-row .right-col {
-    margin-bottom: 16px;
-  }
+.metric-binding-row .left-col,
+.metric-binding-row .right-col {
+  margin-bottom: 16px;
+}
 
-  .metric-binding-row .panel {
-    background: #ffffff;
-    padding: 16px;
-    box-sizing: border-box;
-    height: 100%;
-    min-height: 400px;
-  }
+.metric-binding-row .panel {
+  background: #ffffff;
+  padding: 16px;
+  box-sizing: border-box;
+  height: 100%;
+  min-height: 400px;
+}
 
-  .left-panel,
-  .right-panel {
-    height: 100%;
-  }
+.left-panel,
+.right-panel {
+  height: 100%;
+}
 
-  .toolbar {
-    display: flex;
-    justify-content: space-between;
-    align-items: center;
-    margin-bottom: 12px;
-  }
+.toolbar {
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+  margin-bottom: 12px;
+}
 
-  .toolbar-right {
-    flex-shrink: 0;
-  }
+.toolbar-right {
+  flex-shrink: 0;
+}
 
-  .right-header {
-    display: flex;
-    align-items: baseline;
-    justify-content: space-between;
-    margin-bottom: 10px;
-  }
+.right-header {
+  display: flex;
+  align-items: baseline;
+  justify-content: space-between;
+  margin-bottom: 10px;
+}
 
-  .right-header .title {
-    font-size: 16px;
-    font-weight: 600;
-  }
+.right-header .title {
+  font-size: 16px;
+  font-weight: 600;
+}
 
-  .right-header .desc {
-    font-size: 13px;
-    color: #666;
-  }
+.right-header .desc {
+  font-size: 13px;
+  color: #666;
+}
 
-  .right-toolbar {
-    display: flex;
-    justify-content: flex-end;
-    gap: 10px;
-    margin-bottom: 10px;
-  }
+.right-toolbar {
+  display: flex;
+  justify-content: flex-end;
+  gap: 10px;
+  margin-bottom: 10px;
+}
 
-  .link-text {
-    color: #409eff;
-    cursor: default;
-  }
+.link-text {
+  color: #409eff;
+  cursor: default;
+}
 
-  .clickable-link {
-    color: #409eff;
-    cursor: pointer;
-  }
+.clickable-link {
+  color: #409eff;
+  cursor: pointer;
+}
 
-  .clickable-link:hover {
-    text-decoration: underline;
-  }
+.clickable-link:hover {
+  text-decoration: underline;
+}
 
-  :deep(.row-center td) {
-    text-align: center !important;
-  }
+:deep(.row-center td) {
+  text-align: center !important;
+}
 
-  /* el-table 琛ㄥご/鍐呭缁熶竴灞呬腑锛坮ow-class-name 涓嶄綔鐢ㄤ簬琛ㄥご锛� */
-  :deep(.center-table .el-table__header-wrapper th .cell) {
-    text-align: center !important;
-  }
-  :deep(.center-table .el-table__body-wrapper td .cell) {
-    text-align: center !important;
-  }
+/* el-table 琛ㄥご/鍐呭缁熶竴灞呬腑锛坮ow-class-name 涓嶄綔鐢ㄤ簬琛ㄥご锛� */
+:deep(.center-table .el-table__header-wrapper th .cell) {
+  text-align: center !important;
+}
+:deep(.center-table .el-table__body-wrapper td .cell) {
+  text-align: center !important;
+}
 
-  /* PIMTable 琛ㄥご灞呬腑 */
-  :deep(.lims-table .pim-table-header-cell) {
-    text-align: center;
-    display: flex;
-    flex-direction: column;
-    align-items: center;
-    justify-content: center;
-  }
+/* PIMTable 琛ㄥご灞呬腑 */
+:deep(.lims-table .pim-table-header-cell) {
+  text-align: center;
+  display: flex;
+  flex-direction: column;
+  align-items: center;
+  justify-content: center;
+}
 
-  :deep(.lims-table .pim-table-header-title) {
-    text-align: center;
-    width: 100%;
-  }
+:deep(.lims-table .pim-table-header-title) {
+  text-align: center;
+  width: 100%;
+}
 
-  :deep(.lims-table .pim-table-header-extra) {
-    width: 100%;
-    margin-top: 4px;
-  }
+:deep(.lims-table .pim-table-header-extra) {
+  width: 100%;
+  margin-top: 4px;
+}
+
+.binding-dialog {
+  display: flex;
+  flex-direction: column;
+  gap: 12px;
+}
+
+.binding-search {
+  width: 100%;
+}
+
+.product-binding-tree {
+  max-height: 360px;
+  overflow-y: auto;
+  border: 1px solid #ebeef5;
+  border-radius: 4px;
+  padding: 8px;
+}
+
+.selected-products {
+  border-top: 1px solid #ebeef5;
+  padding-top: 12px;
+}
+
+.selected-title {
+  font-size: 13px;
+  color: #606266;
+  margin-bottom: 8px;
+}
+
+.selected-tags {
+  display: flex;
+  flex-wrap: wrap;
+  gap: 8px;
+}
 </style>

--
Gitblit v1.9.3