From 50552c590564e51349229d4f2e26a147109adc60 Mon Sep 17 00:00:00 2001
From: liding <756868258@qq.com>
Date: 星期五, 27 三月 2026 17:55:07 +0800
Subject: [PATCH] feat:1.生产订单增加领用弹窗(数据输入和输出)

---
 src/views/salesManagement/salesLedger/index.vue |  232 ++++++++++++++++++++++++++++++++++++++++++++++++++++------
 1 files changed, 208 insertions(+), 24 deletions(-)

diff --git a/src/views/salesManagement/salesLedger/index.vue b/src/views/salesManagement/salesLedger/index.vue
index da26ba7..884582d 100644
--- a/src/views/salesManagement/salesLedger/index.vue
+++ b/src/views/salesManagement/salesLedger/index.vue
@@ -37,7 +37,7 @@
         </div>
       </div>
       <el-table :data="tableData" border v-loading="tableLoading" @selection-change="handleSelectionChange"
-        :expand-row-keys="expandedRowKeys" :row-key="(row) => row.id" show-summary style="width: 100%"
+        :expand-row-keys="expandedRowKeys" :row-key="(row) => row.id" :row-class-name="tableRowClassName" show-summary style="width: 100%"
         :summary-method="summarizeMainTable" @expand-change="expandChange" height="calc(100vh - 18.5em)">
         <el-table-column align="center" type="selection" width="55" fixed="left"/>
         <el-table-column type="expand" width="60" fixed="left">
@@ -46,6 +46,7 @@
               <el-table-column align="center" label="搴忓彿" type="index"/>
               <el-table-column label="浜у搧澶х被" prop="productCategory" />
               <el-table-column label="瑙勬牸鍨嬪彿" prop="specificationModel" />
+              <el-table-column label="鎵瑰彿" prop="batchNo" />
               <el-table-column label="鍗曚綅" prop="unit" />
 							<el-table-column label="浜у搧鐘舵��"
 															 width="100px"
@@ -117,11 +118,14 @@
         <el-table-column label="褰曞叆浜�" prop="entryPersonName" width="100" show-overflow-tooltip />
         <el-table-column label="褰曞叆鏃ユ湡" prop="entryDate" width="120" show-overflow-tooltip />
         <el-table-column label="绛捐鏃ユ湡" prop="executionDate" width="120" show-overflow-tooltip />
+        <el-table-column label="浜や粯鏃ユ湡" prop="deliveryDate" width="120" show-overflow-tooltip />
+        <el-table-column label="澶囨敞" prop="remarks" width="200" show-overflow-tooltip />
         <el-table-column fixed="right" label="鎿嶄綔" min-width="100" align="center">
           <template #default="scope">
-            <el-button link type="primary" size="small" @click="openForm('edit', scope.row)">缂栬緫</el-button>
+            <el-button link type="primary" size="small" @click="openForm('edit', scope.row)" :disabled="!scope.row.isEdit">缂栬緫</el-button>
 <!--            <el-button link type="primary" size="small" @click="openForm('view', scope.row)">璇︽儏</el-button>-->
             <el-button link type="primary" size="small" @click="downLoadFile(scope.row)">闄勪欢</el-button>
+            <el-button link type="primary" size="small" @click="exportSaleOutbound(scope.row)">鎵撳嵃閿�鍞嚭搴撳崟</el-button>
 <!--            <el-button link type="primary" size="small" @click="openDeliveryForm(scope.row)">鍙戣揣</el-button>-->
           </template>
         </el-table-column>
@@ -204,6 +208,14 @@
 						</el-form-item>
 					</el-col>
 				</el-row>
+        <el-row :gutter="30">
+          <el-col :span="12">
+            <el-form-item label="浜よ揣鏃ユ湡锛�" prop="entryDate">
+              <el-date-picker style="width: 100%" v-model="form.deliveryDate" value-format="YYYY-MM-DD" format="YYYY-MM-DD"
+                              type="date" placeholder="璇烽�夋嫨" clearable />
+            </el-form-item>
+          </el-col>
+        </el-row>
 				<el-row>
 					<el-form-item label="浜у搧淇℃伅锛�" prop="entryDate">
 						<el-button v-if="operationType !== 'view'" type="primary" @click="openProductForm('add')">娣诲姞</el-button>
@@ -212,10 +224,13 @@
 				</el-row>
 				<el-table :data="productData" border @selection-change="productSelected" show-summary
 									:summary-method="summarizeMainTable">
-					<el-table-column align="center" type="selection" width="55" v-if="operationType !== 'view'" />
+					<el-table-column align="center" type="selection" width="55" v-if="operationType !== 'view'"
+						:selectable="(row) => !isProductShipped(row)" />
 					<el-table-column align="center" label="搴忓彿" type="index" width="60" />
 					<el-table-column label="浜у搧澶х被" prop="productCategory" />
 					<el-table-column label="瑙勬牸鍨嬪彿" prop="specificationModel" />
+					<el-table-column label="UID鐮�" prop="uidNo" />
+					<el-table-column label="鎵瑰彿" prop="batchNo" />
 					<el-table-column label="鍗曚綅" prop="unit" />
 					<el-table-column label="鏁伴噺" prop="quantity" />
 					<el-table-column label="绋庣巼(%)" prop="taxRate" />
@@ -224,20 +239,22 @@
 					<el-table-column label="涓嶅惈绋庢�讳环(鍏�)" prop="taxExclusiveTotalPrice" :formatter="formattedNumber" />
 					<el-table-column fixed="right" label="鎿嶄綔" min-width="60" align="center" v-if="operationType !== 'view'">
 						<template #default="scope">
-							<el-button link type="primary" size="small" @click="openProductForm('edit', scope.row,scope.$index)">缂栬緫</el-button>
+							<el-button link type="primary" size="small" 
+								:disabled="isProductShipped(scope.row)"
+								@click="openProductForm('edit', scope.row,scope.$index)">缂栬緫</el-button>
 						</template>
 					</el-table-column>
 				</el-table>
 				<el-row :gutter="30">
 					<el-col :span="24">
-						<el-form-item label="澶囨敞路锛�" prop="remark">
-							<el-input v-model="form.remark" placeholder="璇疯緭鍏�" clearable type="textarea" :rows="2" :disabled="operationType === 'view'" />
+						<el-form-item label="澶囨敞锛�" prop="remarks">
+							<el-input v-model="form.remarks" placeholder="璇疯緭鍏�" clearable type="textarea" :rows="2" :disabled="operationType === 'view'" />
 						</el-form-item>
 					</el-col>
 				</el-row>
 				<el-row :gutter="30">
 					<el-col :span="24">
-						<el-form-item label="闄勪欢鏉愭枡锛�" prop="remark">
+						<el-form-item label="闄勪欢鏉愭枡锛�" prop="salesLedgerFiles">
 							<el-upload v-model:file-list="fileList" :action="upload.url" multiple ref="fileUpload" auto-upload
 												 :headers="upload.headers" :before-upload="handleBeforeUpload" :on-error="handleUploadError"
 												 :on-success="handleUploadSuccess" :on-remove="handleRemove">
@@ -306,6 +323,15 @@
 				</el-table-column>
 			</el-table>
 			
+			<pagination
+				v-show="quotationPage.total > 0"
+				:total="quotationPage.total"
+				layout="total, sizes, prev, pager, next, jumper"
+				:page="quotationPage.current"
+				:limit="quotationPage.size"
+				@pagination="quotationPaginationChange"
+			/>
+			
 			<template #footer>
 				<el-button @click="quotationDialogVisible = false">鍏抽棴</el-button>
 			</template>
@@ -339,6 +365,15 @@
 						</el-form-item>
 					</el-col>
 				</el-row>
+        <el-row :gutter="30">
+          <el-col :span="24">
+            <el-form-item label="鎵瑰彿锛�" prop="batchNo">
+              <el-select v-model="productForm.batchNo" placeholder="璇烽�夋嫨" clearable filterable>
+                <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="12">
 						<el-form-item label="鍗曚綅锛�" prop="unit">
@@ -644,20 +679,22 @@
 import FormDialog from '@/components/Dialog/FormDialog.vue';
 import { getQuotationList } from "@/api/salesManagement/salesQuotation.js";
 import {
-	ledgerListPage,
-	productList,
-	customerList,
-	addOrUpdateSalesLedger,
-	getSalesLedgerWithProducts,
-	delLedger,
-	addOrUpdateSalesLedgerProduct,
-	delProduct,
-	delLedgerFile, getProductInventory,
+  ledgerListPage,
+  productList,
+  customerList,
+  addOrUpdateSalesLedger,
+  getSalesLedgerWithProducts,
+  delLedger,
+  addOrUpdateSalesLedgerProduct,
+  delProduct,
+  delLedgerFile, getProductInventory, saleOutboundExport,
 } from "@/api/salesManagement/salesLedger.js";
 import { modelList, productTreeList } from "@/api/basicData/product.js";
 import useFormData from "@/hooks/useFormData.js";
 import dayjs from "dayjs";
 import { getCurrentDate } from "@/utils/index.js";
+import {getProductOrderBatchNoOptions} from "@/api/productionManagement/productionOrder.js";
+import {safeTrainingExport} from "@/api/safeProduction/safetyTrainingAssessment.js";
 
 const userStore = useUserStore();
 const { proxy } = getCurrentInstance();
@@ -694,6 +731,7 @@
 		customerId: "",
 		entryPerson: "",
 		entryDate: "",
+    deliveryDate: "",
 		maintenanceTime: "",
 		productData: [],
 		executionDate: "",
@@ -703,6 +741,7 @@
 		customerId: [{ required: true, message: "璇烽�夋嫨", trigger: "change" }],
 		entryPerson: [{ required: true, message: "璇烽�夋嫨", trigger: "change" }],
 		entryDate: [{ required: true, message: "璇烽�夋嫨", trigger: "change" }],
+    deliveryDate: [{ required: true, message: "璇烽�夋嫨", trigger: "change" }],
 		executionDate: [{ required: true, message: "璇烽�夋嫨", trigger: "change" }],
 	},
 });
@@ -723,10 +762,12 @@
 		taxInclusiveTotalPrice: "",
 		taxExclusiveTotalPrice: "",
 		invoiceType: "",
+    batchNo: "",
 	},
 	productRules: {
 		productCategory: [{ required: true, message: "璇烽�夋嫨", trigger: "change" }],
 		productModelId: [{ required: true, message: "璇烽�夋嫨", trigger: "change" }],
+    batchNo: [{ required: true, message: "璇烽�夋嫨", trigger: "change" }],
 		specificationModel: [
 			{ required: true, message: "璇烽�夋嫨", trigger: "change" },
 		],
@@ -765,6 +806,12 @@
 const quotationSearchForm = reactive({
 	quotationNo: "",
 	customer: "",
+});
+// 鎶ヤ环鍗曞脊妗嗗垎椤�
+const quotationPage = reactive({
+	current: 1,
+	size: 10,
+	total: 0,
 });
 const selectedQuotation = ref(null);
 
@@ -987,6 +1034,23 @@
 		expandedRowKeys.value = [];
 	}
 };
+
+// 娣诲姞琛ㄨ绫诲悕鏂规硶
+const tableRowClassName = ({ row }) => {
+  if (!row.deliveryDate) return '';
+  if (row.isFh) return '';
+
+  const diff = row.deliveryDaysDiff;
+  if (diff === 15) {
+    return 'yellow';
+  } else if (diff === 10) {
+    return 'pink';
+  } else if (diff === 2) {
+    return 'purple';
+  } else if (diff < 2) {
+    return 'red';
+  }
+};
 // 涓昏〃鍚堣鏂规硶
 const summarizeMainTable = (param) => {
 	return proxy.summarizeTable(param, [
@@ -1043,6 +1107,8 @@
 const openQuotationDialog = async () => {
 	if (operationType.value === "view") return;
 	quotationDialogVisible.value = true;
+	// 鎵撳紑寮圭獥鏃堕噸缃垎椤靛埌绗竴椤�
+	quotationPage.current = 1;
 	// 鍏堢‘淇濆鎴峰垪琛ㄥ凡鍔犺浇锛屼究浜庡悗缁洖濉� customerId
 	if (!customerOption.value || customerOption.value.length === 0) {
 		try {
@@ -1059,14 +1125,15 @@
 	quotationLoading.value = true;
 	try {
 		const params = {
-			// 鍏煎鍚庣鍒嗛〉瀛楁锛氳繖閲屾部鐢ㄦ姤浠烽〉闈㈠凡鏈夊彲鐢ㄧ殑瀛楁鍛藉悕
-			currentPage: 1,
-			pageSize: 100,
+			// 鍚庣鍒嗛〉瀛楁锛歝urrent / size
+			current: quotationPage.current,
+			size: quotationPage.size,
 			...quotationSearchForm,
 			status: "閫氳繃",
 		};
 		const res = await getQuotationList(params);
 		quotationList.value = res?.data?.records || [];
+		quotationPage.total = res?.data?.total || 0;
 	} finally {
 		quotationLoading.value = false;
 	}
@@ -1075,7 +1142,15 @@
 const resetQuotationSearch = async () => {
 	quotationSearchForm.quotationNo = "";
 	quotationSearchForm.customer = "";
+	quotationPage.current = 1;
 	await fetchQuotationList();
+};
+
+// 鎶ヤ环鍗曞脊妗嗗垎椤靛垏鎹�
+const quotationPaginationChange = (obj) => {
+	quotationPage.current = obj.page;
+	quotationPage.size = obj.limit;
+	fetchQuotationList();
 };
 
 // 閫変腑鎶ヤ环鍗曞悗鍥炲~鍒板彴璐﹁〃鍗�
@@ -1187,6 +1262,12 @@
 		}
 	});
 };
+
+const batchNoOptions = ref([]);
+const fetchBatchNoOptions = async () => {
+	const res = await getProductOrderBatchNoOptions();
+	batchNoOptions.value = res.data;
+};
 // 鍏抽棴寮规
 const closeDia = () => {
 	proxy.resetForm("formRef");
@@ -1196,6 +1277,12 @@
 const productIndex = ref(0);
 // 鎵撳紑浜у搧寮规
 const openProductForm = async (type, row, index) => {
+	// 缂栬緫鏃舵鏌ヤ骇鍝佹槸鍚﹀凡鍙戣揣鎴栧鏍搁�氳繃
+	if (type === "edit" && isProductShipped(row)) {
+		proxy.$modal.msgWarning("宸插彂璐ф垨瀹℃牳閫氳繃鐨勪骇鍝佷笉鑳界紪杈�");
+		return;
+	}
+	
 	productOperationType.value = type;
 	productForm.value = {};
 	proxy.resetForm("productFormRef");
@@ -1262,6 +1349,14 @@
 		proxy.$modal.msgWarning("璇烽�夋嫨鏁版嵁");
 		return;
 	}
+	
+	// 妫�鏌ユ槸鍚︽湁宸插彂璐ф垨瀹℃牳閫氳繃鐨勪骇鍝�
+	const shippedProducts = productSelectedRows.value.filter(row => isProductShipped(row));
+	if (shippedProducts.length > 0) {
+		proxy.$modal.msgWarning("宸插彂璐ф垨瀹℃牳閫氳繃鐨勪骇鍝佷笉鑳藉垹闄�");
+		return;
+	}
+	
 	if (operationType.value === "add") {
 		productSelectedRows.value.forEach((selectedRow) => {
 			const index = productData.value.findIndex(
@@ -1336,15 +1431,55 @@
 			proxy.$modal.msg("宸插彇娑�");
 		});
 };
+/** 鍒ゆ柇鍗曚釜浜у搧鏄惁宸插彂璐э紙鏍规嵁shippingStatus鍒ゆ柇锛屽凡鍙戣揣鎴栧鏍搁�氳繃涓嶅彲缂栬緫鍜屽垹闄わ級 */
+const isProductShipped = (product) => {
+	if (!product) return false;
+	const status = String(product.shippingStatus || "").trim();
+	// 濡傛灉鍙戣揣鐘舵�佹槸"宸插彂璐�"鎴�"瀹℃牳閫氳繃"锛屽垯涓嶅彲缂栬緫鍜屽垹闄�
+	return status === "宸插彂璐�" || status === "瀹℃牳閫氳繃";
+};
+
+/** 鍒ゆ柇閿�鍞鍗曚笅鏄惁瀛樺湪宸插彂璐�/鍙戣揣瀹屾垚鐨勪骇鍝侊紙涓嶅彲鍒犻櫎锛� */
+const hasShippedProducts = (products) => {
+	if (!products || !products.length) return false;
+	return products.some((p) => {
+		const status = String(p.shippingStatus || "").trim();
+		// 鏈夊彂璐ф棩鏈熸垨杞︾墝鍙疯涓哄凡鍙戣揣
+		if (p.shippingDate || p.shippingCarNumber) return true;
+		// 宸茶繘琛屽彂璐с�佸彂璐у畬鎴愩�佸凡鍙戣揣 鍧囦笉鍙垹闄�
+		return status === "宸茶繘琛屽彂璐�" || status === "鍙戣揣瀹屾垚" || status === "宸插彂璐�";
+	});
+};
+
 // 鍒犻櫎
-const handleDelete = () => {
-	let ids = [];
-	if (selectedRows.value.length > 0) {
-		ids = selectedRows.value.map((item) => item.id);
-	} else {
+const handleDelete = async () => {
+	if (selectedRows.value.length === 0) {
 		proxy.$modal.msgWarning("璇烽�夋嫨鏁版嵁");
 		return;
 	}
+	const ids = selectedRows.value.map((item) => item.id);
+
+	// 妫�鏌ユ槸鍚︽湁宸茶繘琛屽彂璐ф垨鍙戣揣瀹屾垚鐨勯攢鍞鍗曪紝鑻ユ湁鍒欎笉鍏佽鍒犻櫎
+	const cannotDeleteNames = [];
+	for (const row of selectedRows.value) {
+		let products = row.children && row.children.length > 0 ? row.children : null;
+		if (!products) {
+			try {
+				const res = await productList({ salesLedgerId: row.id, type: 1 });
+				products = res.data || [];
+			} catch {
+				products = [];
+			}
+		}
+		if (hasShippedProducts(products)) {
+			cannotDeleteNames.push(row.salesContractNo || `ID:${row.id}`);
+		}
+	}
+	if (cannotDeleteNames.length > 0) {
+		proxy.$modal.msgWarning("宸茶繘琛屽彂璐ф垨鍙戣揣瀹屾垚鐨勯攢鍞鍗曚笉鑳藉垹闄わ細" + cannotDeleteNames.join("銆�"));
+		return;
+	}
+
 	ElMessageBox.confirm("閫変腑鐨勫唴瀹瑰皢琚垹闄わ紝鏄惁纭鍒犻櫎锛�", "瀵煎嚭", {
 		confirmButtonText: "纭",
 		cancelButtonText: "鍙栨秷",
@@ -2070,8 +2205,41 @@
 	let res = await userStore.getInfo();
 	currentFactoryName.value = res.user.currentFactoryName;
 };
+
+const exportSaleOutbound = row => {
+  saleOutboundExport({id: row.id})
+      .then(res => {
+        // 鍒涘缓Blob瀵硅薄
+        const blob = new Blob([res], {
+          type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
+        });
+        // 鍒涘缓涓嬭浇閾炬帴
+        const url = window.URL.createObjectURL(blob);
+        const link = document.createElement("a");
+        link.href = url;
+        link.download = `閿�鍞嚭搴撳崟.docx`;
+
+        // 妯℃嫙鐐瑰嚮涓嬭浇
+        document.body.appendChild(link);
+        link.click();
+
+        // 娓呯悊涓存椂瀵硅薄
+        setTimeout(() => {
+          document.body.removeChild(link);
+          window.URL.revokeObjectURL(url);
+        }, 100);
+
+        ElMessage.success("瀵煎嚭鎴愬姛");
+      })
+      .catch(err => {
+        console.error("瀵煎嚭澶辫触:", err);
+        ElMessage.error("瀵煎嚭澶辫触锛岃閲嶈瘯");
+      });
+};
+
 onMounted(() => {
 	getList();
+  fetchBatchNoOptions();
 	userListNoPage().then(res => {
 		userList.value = res.data;
 	})
@@ -2084,6 +2252,22 @@
 	margin-left: 10px;
 }
 
+::v-deep .yellow {
+  background-color: #FAF0DE;
+}
+
+::v-deep .pink {
+  background-color: #FAE1DE;
+}
+
+::v-deep .red {
+  background-color: #FAE1DE;
+}
+
+::v-deep .purple{
+  background-color: #F4DEFA;
+}
+
 .table_list {
 	margin-top: unset;
 }

--
Gitblit v1.9.3