From bb91952d1f1f59c4719d77eaf56e47eafa10126a Mon Sep 17 00:00:00 2001
From: yuan <123@>
Date: 星期三, 21 十月 2026 17:20:55 +0800
Subject: [PATCH] feat: 添加产品树过滤功能,支持新增和编辑场景下的产品类别选择

---
 src/views/procurementManagement/procurementLedger/index.vue |   10 ++++
 src/views/productionPlan/productionPlan/index.vue           |    9 ++++
 src/utils/productTree.js                                    |   59 +++++++++++++++++++++++++++++
 3 files changed, 76 insertions(+), 2 deletions(-)

diff --git a/src/utils/productTree.js b/src/utils/productTree.js
new file mode 100644
index 0000000..4d4eaa0
--- /dev/null
+++ b/src/utils/productTree.js
@@ -0,0 +1,59 @@
+/**
+ * 浜у搧澶х被鏍戯紙/basic/product/list锛夊伐鍏�
+ *
+ * 璇存槑锛氫骇鍝佹爲涓�绾ц妭鐐规槸銆屾垚鍝� / 鍗婃垚鍝� / 鍘熸潗鏂欍�嶈繖绫绘牴鑺傜偣锛屽叿浣撲骇鍝佸ぇ绫绘寕鍦ㄦ牴鑺傜偣涓嬨��
+ * 閮ㄥ垎涓氬姟鏂板鏃跺彧鍏佽閫夋嫨鏌愪竴绫讳骇鍝侊紙濡傞噰璐彴璐﹀彧閫夊師鏉愭枡銆佺敓浜ц鍒掑彧閫夋垚鍝侊級锛岀紪杈戞椂瑕佷繚鎸佸畬鏁存爲銆�
+ */
+
+// 鏍硅妭鐐瑰悕绉帮紝鍏煎銆屽師鏉愭枡銆嶃�屽師鏂欍�嶄袱绉嶅缓娉�
+const RAW_MATERIAL_ROOT_NAMES = ["鍘熸潗鏂�", "鍘熸枡"];
+const FINISHED_PRODUCT_ROOT_NAMES = ["鎴愬搧"];
+
+/**
+ * 鍙栬妭鐐瑰悕绉帮紙鏍戞帴鍙e悓鏃惰繑鍥� label 涓� productName锛�
+ * @param {object} node 鏍戣妭鐐�
+ * @returns {string} 鑺傜偣鍚嶇О
+ */
+const getNodeLabel = node =>
+  String(node?.label ?? node?.productName ?? "").trim();
+
+/**
+ * 鍒ゆ柇鑺傜偣鍚嶇О鏄惁鍛戒腑鎸囧畾鐨勬牴鑺傜偣鍚嶇О锛堝畬鍏ㄧ浉鍚屾垨浠ヨ鍚嶇О寮�澶达級
+ * @param {object} node 鏍戣妭鐐�
+ * @param {Array<string>} rootNames 鍏佽鐨勬牴鑺傜偣鍚嶇О
+ * @returns {boolean} 鏄惁鍛戒腑
+ */
+const isRootNodeNamed = (node, rootNames) => {
+  const label = getNodeLabel(node);
+  if (!label) {
+    return false;
+  }
+  return rootNames.some(name => label === name || label.startsWith(name));
+};
+
+/**
+ * 鍙繚鐣欐寚瀹氬悕绉版牴鑺傜偣涓嬬殑浜у搧鏍戯紝鐢ㄤ簬鏂板鍦烘櫙
+ * @param {Array} tree 鎺ュ彛杩斿洖鐨勪骇鍝佹爲
+ * @param {Array<string>} rootNames 鍏佽鐨勬牴鑺傜偣鍚嶇О
+ * @returns {Array} 杩囨护鍚庣殑鏍戯紙涓嶆敼鍔ㄥ師鏁版嵁锛岀紪杈戝満鏅洿鎺ヤ紶鍘熸爲鍗冲彲锛�
+ */
+export const filterProductTreeByRoot = (tree, rootNames = []) =>
+  (Array.isArray(tree) ? tree : []).filter(node =>
+    isRootNodeNamed(node, rootNames)
+  );
+
+/**
+ * 鍙繚鐣欍�屽師鏉愭枡銆嶆牴鑺傜偣涓嬬殑浜у搧鏍�
+ * @param {Array} tree 鎺ュ彛杩斿洖鐨勪骇鍝佹爲
+ * @returns {Array} 杩囨护鍚庣殑鏍�
+ */
+export const filterRawMaterialTree = tree =>
+  filterProductTreeByRoot(tree, RAW_MATERIAL_ROOT_NAMES);
+
+/**
+ * 鍙繚鐣欍�屾垚鍝併�嶆牴鑺傜偣涓嬬殑浜у搧鏍�
+ * @param {Array} tree 鎺ュ彛杩斿洖鐨勪骇鍝佹爲
+ * @returns {Array} 杩囨护鍚庣殑鏍�
+ */
+export const filterFinishedProductTree = tree =>
+  filterProductTreeByRoot(tree, FINISHED_PRODUCT_ROOT_NAMES);
diff --git a/src/views/procurementManagement/procurementLedger/index.vue b/src/views/procurementManagement/procurementLedger/index.vue
index b28df5d..86aeb7d 100644
--- a/src/views/procurementManagement/procurementLedger/index.vue
+++ b/src/views/procurementManagement/procurementLedger/index.vue
@@ -547,7 +547,7 @@
                               filterable
                               check-strictly
                               @change="getModels"
-                              :data="productOptions"
+                              :data="productFormOptions"
                               :render-after-expand="false"
                               style="width: 100%" />
             </el-form-item>
@@ -705,6 +705,7 @@
     onMounted,
     reactive,
     toRefs,
+    computed,
     getCurrentInstance,
     nextTick,
   } from "vue";
@@ -762,6 +763,7 @@
   import dayjs from "dayjs";
   import FileUpload from "@/components/AttachmentUpload/file/index.vue";
   import { roundHalfUp, trimZeros } from "@/utils/formatNumber.js";
+  import { filterRawMaterialTree } from "@/utils/productTree.js";
 
   const userStore = useUserStore();
 
@@ -959,6 +961,12 @@
   // 浜у搧琛ㄥ崟寮规鏁版嵁
   const productFormVisible = ref(false);
   const productOperationType = ref("");
+  // 鏂板浜у搧鏃朵骇鍝佸ぇ绫诲彧灞曠ず銆屽師鏉愭枡銆嶏紝缂栬緫鏃朵繚鎸佸畬鏁翠骇鍝佹爲
+  const productFormOptions = computed(() =>
+    productOperationType.value === "add"
+      ? filterRawMaterialTree(productOptions.value)
+      : productOptions.value
+  );
   const productOperationIndex = ref("");
   const currentId = ref("");
   const productFormData = reactive({
diff --git a/src/views/productionPlan/productionPlan/index.vue b/src/views/productionPlan/productionPlan/index.vue
index fd6c1a3..e254c57 100644
--- a/src/views/productionPlan/productionPlan/index.vue
+++ b/src/views/productionPlan/productionPlan/index.vue
@@ -186,7 +186,7 @@
           <el-tree-select v-model="form.productId"
                           placeholder="璇烽�夋嫨"
                           clearable
-                          :data="productOptions"
+                          :data="productTreeOptions"
                           :render-after-expand="false"
                           filterable
                           @change="handleProductChange"
@@ -283,6 +283,7 @@
     exportProductionPlan,
   } from "@/api/productionPlan/productionPlan.js";
   import { productTreeList, modelListPage } from "@/api/basicData/product.js";
+  import { filterFinishedProductTree } from "@/utils/productTree.js";
   import PIMTable from "./components/PIMTable.vue";
   import ImportDialog from "@/components/Dialog/ImportDialog.vue";
 
@@ -510,6 +511,12 @@
   const dialogVisible = ref(false);
   const operationType = ref("add"); // add | edit
   const productOptions = ref([]);
+  // 鏂板鐢熶骇璁″垝鏃朵骇鍝佸悕绉板彧灞曠ず銆屾垚鍝併�嶏紝缂栬緫鏃朵繚鎸佸畬鏁翠骇鍝佹爲
+  const productTreeOptions = computed(() =>
+    operationType.value === "add"
+      ? filterFinishedProductTree(productOptions.value)
+      : productOptions.value
+  );
   const specificationOptions = ref([]);
   const queryRef = ref(null);
   const formRef = ref(null);

--
Gitblit v1.9.3