From b937241a2c20f62f45b31b232b6cebdec03d41d7 Mon Sep 17 00:00:00 2001
From: spring <2396852758@qq.com>
Date: 星期二, 31 三月 2026 15:57:42 +0800
Subject: [PATCH] fix: 销售批号

---
 src/views/salesManagement/salesLedger/index.vue |  304 +++++++++++++++++++++++++++++++++++++++-----------
 1 files changed, 238 insertions(+), 66 deletions(-)

diff --git a/src/views/salesManagement/salesLedger/index.vue b/src/views/salesManagement/salesLedger/index.vue
index 8475b25..4e1f8ee 100644
--- a/src/views/salesManagement/salesLedger/index.vue
+++ b/src/views/salesManagement/salesLedger/index.vue
@@ -376,8 +376,25 @@
         <el-row :gutter="30">
           <el-col :span="24">
             <el-form-item label="鎵瑰彿锛�" prop="batchNo">
-              <el-select v-model="productForm.batchNo" placeholder="璇烽�夋嫨" clearable filterable>
+              <el-select v-model="productForm.batchNo"
+                          placeholder="璇烽�夋嫨"
+                          clearable
+                          filterable
+                          @change="handleBatchNoChange">
                 <el-option v-for="item in batchNoOptions" :key="item.value" :label="item.label" :value="item.value" />
+              </el-select>
+            </el-form-item>
+          </el-col>
+        </el-row>
+        <el-row :gutter="30">
+          <el-col :span="24">
+            <el-form-item label="渚涘簲鍟嗭細" prop="customer">
+              <el-select v-model="productForm.customer"
+                          placeholder="璇烽�夋嫨"
+                          clearable
+                          filterable
+                          :disabled="!supplierOptions.length">
+                <el-option v-for="item in supplierOptions" :key="item.value" :label="item.label" :value="item.value" />
               </el-select>
             </el-form-item>
           </el-col>
@@ -697,11 +714,11 @@
   delProduct,
   delLedgerFile, getProductInventory, saleOutboundExport,
 } from "@/api/salesManagement/salesLedger.js";
-import { modelList, productTreeList } from "@/api/basicData/product.js";
+import { getStockInventoryAll } from "@/api/inventoryManagement/stockInventory.js";
 import useFormData from "@/hooks/useFormData.js";
 import dayjs from "dayjs";
 import { getCurrentDate } from "@/utils/index.js";
-import {getProductOrderBatchNoOptions} from "@/api/productionManagement/productionOrder.js";
+// 鐢� /stockInventory/getStockInventoryAll 椹卞姩鈥滄壒鍙�/渚涘簲鍟嗏�濊仈鍔�
 import {safeTrainingExport} from "@/api/safeProduction/safetyTrainingAssessment.js";
 
 const userStore = useUserStore();
@@ -714,6 +731,7 @@
 const customerOption = ref([]);
 const productOptions = ref([]);
 const modelOptions = ref([]);
+const supplierOptions = ref([]);
 const tableLoading = ref(false);
 const page = reactive({
 	current: 1,
@@ -762,6 +780,7 @@
 const productFormData = reactive({
 	productForm: {
 		productCategory: "",
+		customer: "",
 		specificationModel: "",
     uidNo: "",
 		unit: "",
@@ -777,6 +796,7 @@
 		productCategory: [{ required: true, message: "璇烽�夋嫨", trigger: "change" }],
 		productModelId: [{ required: true, message: "璇烽�夋嫨", trigger: "change" }],
     batchNo: [{ required: true, message: "璇烽�夋嫨", trigger: "change" }],
+		customer: [{ required: true, message: "璇烽�夋嫨", trigger: "change" }],
 		specificationModel: [
 			{ required: true, message: "璇烽�夋嫨", trigger: "change" },
 		],
@@ -945,64 +965,202 @@
 			tableLoading.value = false;
 		});
 };
-// 鑾峰彇浜у搧澶х被tree鏁版嵁
-const getProductOptions = () => {
+let stockInventoryAllTree = [];
+let batchNodeByBatchNo = new Map();
+
+const normalizeStockInventoryTree = (nodes = []) => {
+	const normalizeNodeValue = (node) => {
+		// 鍚庣鏈夋椂浼氬嚭鐜� id=null 鐨勫眰绾э紝杩欓噷缁欎竴涓彲鐢ㄧ殑 key
+		if (node?.id !== null && node?.id !== undefined) return String(node.id);
+		if (node?.nodeType === "batch") return String(node.batchNo ?? node.label ?? "");
+		if (node?.nodeType === "customer") return String(node.customer ?? node.label ?? "");
+		if (node?.nodeType === "model") return String(node.model ?? node.label ?? "");
+		return String(node.productName ?? node.label ?? "");
+	};
+
+	const normalized = (list) =>
+		(list || []).map((n) => {
+			const value = normalizeNodeValue(n);
+			const label = n.label ?? n.productName ?? n.model ?? n.batchNo ?? n.customer ?? "";
+			return {
+				...n,
+				value,
+				label,
+				children: normalized(n.children),
+			};
+		});
+
+	return normalized(nodes);
+};
+
+// 浠呭睍绀烘渶澶� 3 涓眰绾э細绗� 1 灞�(product) -> 绗� 2 灞�(model) -> 绗� 3 灞�(batch)锛屾洿娣辩殑鑺傜偣涓嶅睍绀�
+const filterStockInventoryFirst3Levels = (nodes = []) => {
+	const MAX_LEVEL = 3;
+
+	const cloneAndFilterByLevel = (list = [], level = 1) => {
+		return (list || [])
+			.map((n) => {
+				// 鍚庣画灞傜骇閲屽鏋滆繕鏈� customer锛岀洿鎺ュ墧闄�
+				if (n.nodeType === "customer") return null;
+
+				// 鍒拌揪灞曠ず娣卞害鍚庯紝涓嶅啀鍚戜笅鎸傚瓙鑺傜偣
+				if (level >= MAX_LEVEL) {
+					return { ...n, children: [] };
+				}
+
+				// 鐗逛緥锛歜atch 鑺傜偣鏈韩涔熶笉鍐嶅睍绀� children锛堜繚鎸佷笌鎺ュ彛鑺傜偣璇箟涓�鑷达級
+				if (n.nodeType === "batch") {
+					return { ...n, children: [] };
+				}
+
+				return { ...n, children: cloneAndFilterByLevel(n.children, level + 1) };
+			})
+			.filter(Boolean);
+	};
+
+	return cloneAndFilterByLevel(nodes, 1);
+};
+
+const findNodeObjByValue = (nodes = [], value) => {
+	for (let i = 0; i < (nodes || []).length; i++) {
+		const node = nodes[i];
+		if (String(node?.value) === String(value)) return node;
+		const children = node?.children || [];
+		if (children.length) {
+			const found = findNodeObjByValue(children, value);
+			if (found) return found;
+		}
+	}
+	return null;
+};
+
+// 鑾峰彇搴撳瓨鏍戯紙鐢ㄤ簬浜у搧澶х被/瑙勬牸鍨嬪彿鑱斿姩锛�
+const getProductOptions = async () => {
 	// 杩斿洖 Promise锛屼究浜庡湪缂栬緫浜у搧鏃剁瓑寰呭姞杞藉畬鎴�
-	return productTreeList().then((res) => {
-		productOptions.value = convertIdToValue(res);
-		return productOptions.value;
-	});
+	const res = await getStockInventoryAll();
+	const data = res?.data || [];
+	stockInventoryAllTree = normalizeStockInventoryTree(data);
+	productOptions.value = filterStockInventoryFirst3Levels(stockInventoryAllTree);
+	return productOptions.value;
 };
 const formattedNumber = (row, column, cellValue) => {
 	return parseFloat(cellValue).toFixed(2);
 };
-// 鑾峰彇tree瀛愭暟鎹�
+// 鑾峰彇tree瀛愭暟鎹紙鍏堥�変骇鍝侊紝鍐嶉�夎鏍煎瀷鍙凤級
 const getModels = (value) => {
-	productForm.value.productCategory = findNodeById(productOptions.value, value);
-	modelList({ id: value }).then((res) => {
-		modelOptions.value = res;
-	});
+	const node = findNodeObjByValue(stockInventoryAllTree, value);
+	if (!node) return;
+	if (node.nodeType !== "product") return;
+
+	// 閫夋嫨浜у搧鍚庯紝閲嶇疆涓嬫父瀛楁
+	productForm.value.productCategory = node.label;
+	modelOptions.value = (node.children || [])
+		.filter((c) => c.nodeType === "model")
+		.map((m) => ({
+			id: m.value,
+			model: m.model ?? m.label ?? "",
+			unit: m.unit ?? "",
+			uidNo: m.uidNo ?? m.identifierCode ?? "",
+		}));
+
+	productForm.value.productModelId = null;
+	productForm.value.specificationModel = "";
+	productForm.value.uidNo = "";
+	productForm.value.unit = "";
+	productForm.value.batchNo = "";
+	productForm.value.customer = "";
+	productForm.value.taxInclusiveUnitPrice = "";
+	productForm.value.taxInclusiveTotalPrice = "";
+	productForm.value.taxExclusiveTotalPrice = "";
+
+	modelOptions.value = modelOptions.value || [];
+	batchNoOptions.value = [];
+	supplierOptions.value = [];
+	batchNodeByBatchNo = new Map();
 };
+
+// 瑙勬牸鍨嬪彿閫夋嫨鍚庯細鍥炴樉 UID锛屽苟鐢熸垚鈥滄壒鍙蜂笅鎷夆��
 const getProductModel = (value) => {
-	const index = modelOptions.value.findIndex((item) => item.id === value);
-	if (index !== -1) {
-		productForm.value.specificationModel = modelOptions.value[index].model;
-		productForm.value.unit = modelOptions.value[index].unit;
-    productForm.value.uidNo = modelOptions.value[index].uidNo || "";
+	const modelNode = findNodeObjByValue(stockInventoryAllTree, value);
+	if (!modelNode || modelNode.nodeType !== "model") return;
+
+	const prevBatchNo = productForm.value.batchNo;
+	const prevCustomer = productForm.value.customer;
+
+	productForm.value.specificationModel = modelNode.model ?? modelNode.label ?? "";
+	// 鏈変簺鎺ュ彛/鏍戞暟鎹噷鍙兘涓嶅寘鍚� unit锛岃繖绉嶆儏鍐典笅涓嶈瑕嗙洊缂栬緫鏃跺凡鍥炴樉鐨勫��
+	const nextUnit = modelNode.unit ?? "";
+	if (nextUnit !== null && nextUnit !== undefined && String(nextUnit).trim() !== "") {
+		productForm.value.unit = nextUnit;
+	}
+	// 鏈変簺鎺ュ彛/鏍戞暟鎹噷鍙兘涓嶅寘鍚� uidNo锛岃繖绉嶆儏鍐典笅涓嶈瑕嗙洊缂栬緫鏃跺凡鍥炴樉鐨勫��
+	const nextUidNo = modelNode.uidNo ?? modelNode.identifierCode ?? "";
+	if (nextUidNo !== null && nextUidNo !== undefined && String(nextUidNo).trim() !== "") {
+		productForm.value.uidNo = nextUidNo;
+	}
+
+	const batchNodes = (modelNode.children || []).filter((b) => b.nodeType === "batch");
+	batchNodeByBatchNo = new Map(
+		batchNodes.map((b) => {
+			const key = String(b.batchNo ?? b.value ?? b.label ?? "").trim();
+			return [key, b];
+		})
+	);
+	batchNoOptions.value = batchNodes.map((b) => ({
+		label: String(b.batchNo ?? b.label ?? "").trim(),
+		value: String(b.batchNo ?? b.value ?? b.label ?? "").trim(),
+	}));
+
+	// 鎵瑰彿涓嶅啀灞炰簬鏂拌鏍兼椂锛屾竻绌�
+	const batchValues = new Set(batchNoOptions.value.map((x) => x.value));
+	if (!prevBatchNo || !batchValues.has(prevBatchNo)) {
+		productForm.value.batchNo = "";
+	}
+
+	// 闇�瑕佷緵搴斿晢锛氭壒鍙峰洖鏄惧悗鍐嶇敓鎴�
+	productForm.value.customer = "";
+	supplierOptions.value = [];
+	if (productForm.value.batchNo) {
+		handleBatchNoChange(productForm.value.batchNo, prevCustomer);
+	}
+};
+
+const handleBatchNoChange = (batchNo, prevCustomer) => {
+	const safeBatchNo = String(batchNo ?? "").trim();
+	if (!safeBatchNo || !batchNodeByBatchNo.size) {
+		productForm.value.customer = "";
+		supplierOptions.value = [];
+		return;
+	}
+
+	const batchNode = batchNodeByBatchNo.get(String(safeBatchNo));
+	if (!batchNode) {
+		productForm.value.customer = "";
+		supplierOptions.value = [];
+		return;
+	}
+
+	// UID鐮佸彲鑳芥潵婧愪簬 batch 鑺傜偣锛堜笉鍚屾帴鍙e瓧娈靛悕涓嶄竴鑷存椂灏介噺鍏滃簳锛�
+	const nextUidNo = batchNode.uidNo ?? batchNode.identifierCode ?? batchNode.uid ?? "";
+	if (nextUidNo !== null && nextUidNo !== undefined && String(nextUidNo).trim() !== "") {
+		productForm.value.uidNo = nextUidNo;
+	}
+
+	const customers = (batchNode.children || [])
+		.filter((c) => c.nodeType === "customer")
+		.map((c) => c.customer ?? c.label ?? "")
+		.filter(Boolean);
+
+	const uniq = Array.from(new Set(customers));
+	supplierOptions.value = uniq.map((s) => ({ label: s, value: s }));
+
+	// 缂栬緫鍦烘櫙灏介噺鍥炴樉锛涙柊澧炲満鏅笉鍥炴樉
+	if (prevCustomer && uniq.includes(prevCustomer)) {
+		productForm.value.customer = prevCustomer;
 	} else {
-		productForm.value.specificationModel = null;
-		productForm.value.unit = null;
-		productForm.value.uidNo = null;
+		productForm.value.customer = "";
 	}
 };
-const findNodeById = (nodes, productId) => {
-	for (let i = 0; i < nodes.length; i++) {
-		if (nodes[i].value === productId) {
-			return nodes[i].label; // 鎵惧埌鑺傜偣锛岃繑鍥炶鑺傜偣
-		}
-		if (nodes[i].children && nodes[i].children.length > 0) {
-			const foundNode = findNodeById(nodes[i].children, productId);
-			if (foundNode) {
-				return foundNode; // 鍦ㄥ瓙鑺傜偣涓壘鍒帮紝杩斿洖璇ヨ妭鐐�
-			}
-		}
-	}
-	return null; // 娌℃湁鎵惧埌鑺傜偣锛岃繑鍥瀗ull
-};
-function convertIdToValue(data) {
-	return data.map((item) => {
-		const { id, children, ...rest } = item;
-		const newItem = {
-			...rest,
-			value: id, // 灏� id 鏀逛负 value
-		};
-		if (children && children.length > 0) {
-			newItem.children = convertIdToValue(children);
-		}
-		
-		return newItem;
-	});
-}
 // 鏍规嵁鍚嶇О鍙嶆煡浜у搧澶х被 id锛屼究浜庝粎瀛樺悕绉版椂鐨勫弽鏄�
 function findNodeIdByLabel(nodes, label) {
 	if (!label) return null;
@@ -1276,10 +1434,6 @@
 };
 
 const batchNoOptions = ref([]);
-const fetchBatchNoOptions = async () => {
-	const res = await getProductOrderBatchNoOptions();
-	batchNoOptions.value = res.data;
-};
 // 鍏抽棴寮规
 const closeDia = () => {
 	proxy.resetForm("formRef");
@@ -1303,25 +1457,44 @@
 		productIndex.value = index;
 		// 缂栬緫鏃舵牴鎹骇鍝佸ぇ绫诲悕绉板弽鏌� tree 鑺傜偣 id锛屽苟鍔犺浇瑙勬牸鍨嬪彿鍒楄〃
 		try {
-			const options = productOptions.value && productOptions.value.length > 0
-				? productOptions.value
-				: await getProductOptions();
-			const categoryId = findNodeIdByLabel(options, productForm.value.productCategory);
-			if (categoryId) {
-				const models = await modelList({ id: categoryId });
-				modelOptions.value = models || [];
-				// 鏍规嵁褰撳墠瑙勬牸鍨嬪彿鍚嶇О鍙嶆煡骞惰缃� productModelId锛屼究浜庝笅鎷夋鏄剧ず宸查�夊��
-				const currentModel = (modelOptions.value || []).find(
-					(m) => m.model === productForm.value.specificationModel
-				);
+			if (!productOptions.value || productOptions.value.length === 0) {
+				await getProductOptions();
+			}
+
+			// 鍥炴樉锛氭牴鎹�滀骇鍝佸ぇ绫烩�濆弽鏌ヤ骇鍝佽妭鐐�
+			const categoryKey = findNodeIdByLabel(productOptions.value, productForm.value.productCategory);
+			if (categoryKey) {
+				const categoryNode = findNodeObjByValue(stockInventoryAllTree, categoryKey);
+				const models = (categoryNode?.children || [])
+					.filter((n) => n.nodeType === "model")
+					.map((m) => ({
+						id: m.value,
+						model: m.model ?? m.label ?? "",
+						unit: m.unit ?? "",
+						uidNo: m.uidNo ?? m.identifierCode ?? "",
+					}));
+				modelOptions.value = models;
+
+				// 鏍规嵁褰撳墠瑙勬牸鍨嬪彿鍥炴樉
+				const targetSpec = String(productForm.value.specificationModel ?? "").trim();
+				const currentModel =
+					(models || []).find((m) => String(m.model ?? "").trim() === targetSpec) ||
+					(models || []).find((m) => String(m.model ?? "").trim().includes(targetSpec)) ||
+					(models || []).find((m) => targetSpec.includes(String(m.model ?? "").trim()));
 				if (currentModel) {
+					productForm.value.customer = productForm.value.customer || row.customer || row.supplierName || "";
 					productForm.value.productModelId = currentModel.id;
+					getProductModel(currentModel.id);
 				}
 			}
 		} catch (e) {
 			// 鍔犺浇澶辫触鏃朵繚鎸佸彲缂栬緫锛屼笉涓柇寮圭獥
 			console.error("鍔犺浇浜у搧瑙勬牸鍨嬪彿澶辫触", e);
 		}
+		// 鏈�缁堝厹搴曪細濡傛灉涓�旇閲嶇疆娓呯┖锛岃嚦灏戝洖鏄捐鏁版嵁閲岀殑 UID
+		productForm.value.uidNo = row.uidNo ?? productForm.value.uidNo ?? "";
+		// 鏈�缁堝厹搴曪細鍚屾牱淇濊瘉鍗曚綅涓嶄細鍥犳爲鏁版嵁缂哄け鑰岃瑕嗙洊涓虹┖
+		productForm.value.unit = row.unit ?? productForm.value.unit ?? "";
 	} else {
 		getProductOptions()
 	}
@@ -2251,7 +2424,6 @@
 
 onMounted(() => {
 	getList();
-  fetchBatchNoOptions();
 	userListNoPage().then(res => {
 		userList.value = res.data;
 	})

--
Gitblit v1.9.3