From 168c23ac6a1c021407f905323525c8d411857e57 Mon Sep 17 00:00:00 2001
From: buhuazhen <hua100783@gmail.com>
Date: 星期四, 26 三月 2026 16:36:57 +0800
Subject: [PATCH] fix: 修正销售发货验证并优化黑名单表单显示

---
 src/views/salesManagement/salesLedger/index.vue |  591 +++++++++++++++++++++++++++++++++++++++++++---------------
 1 files changed, 433 insertions(+), 158 deletions(-)

diff --git a/src/views/salesManagement/salesLedger/index.vue b/src/views/salesManagement/salesLedger/index.vue
index da26ba7..97c7b3d 100644
--- a/src/views/salesManagement/salesLedger/index.vue
+++ b/src/views/salesManagement/salesLedger/index.vue
@@ -10,10 +10,6 @@
           <el-input v-model="searchForm.salesContractNo" placeholder="璇疯緭鍏�" clearable prefix-icon="Search"
             @change="handleQuery" />
         </el-form-item>
-        <el-form-item label="椤圭洰鍚嶇О锛�">
-          <el-input v-model="searchForm.projectName" placeholder="璇疯緭鍏�" clearable prefix-icon="Search"
-            @change="handleQuery" />
-        </el-form-item>
         <el-form-item label="褰曞叆鏃ユ湡锛�">
           <el-date-picker v-model="searchForm.entryDate" value-format="YYYY-MM-DD" format="YYYY-MM-DD" type="daterange"
             placeholder="璇烽�夋嫨" clearable @change="changeDaterange" />
@@ -37,7 +33,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">
@@ -64,28 +60,12 @@
 									</el-tag>
 								</template>
 							</el-table-column>
-							<el-table-column label="蹇�掑叕鍙�" prop="expressCompany" show-overflow-tooltip />
-							<el-table-column label="蹇�掑崟鍙�" prop="expressNumber" show-overflow-tooltip />
-              <el-table-column label="鍙戣揣杞︾墝" minWidth="100px" align="center">
-                <template #default="scope">
-                  <div>
-                    <el-tag type="success" v-if="scope.row.shippingCarNumber">{{ scope.row.shippingCarNumber }}</el-tag>
-                    <el-tag v-else type="info">-</el-tag>
-                  </div>
-                </template>
-              </el-table-column>
-							<el-table-column label="鍙戣揣鏃ユ湡"
-															 minWidth="100px"
-															 align="center">
-                <template #default="scope">
-                  <div>
-                    <div v-if="scope.row.shippingDate">{{ scope.row.shippingDate }}</div>
-										<el-tag v-else
-														type="info">-</el-tag>
-                  </div>
-                </template>
-              </el-table-column>
-              <el-table-column label="鏁伴噺" prop="quantity" />
+              <el-table-column label="鏁伴噺" prop ="quantity" />
+					<el-table-column label="宸插彂璐ф暟閲�" prop="partSendAmount" >
+						<template #default="scope">
+										{{ scope.row.partSendAmount || 0 }}
+								</template>
+						</el-table-column>
               <el-table-column label="绋庣巼(%)" prop="taxRate" />
               <el-table-column label="鍚◣鍗曚环(鍏�)" prop="taxInclusiveUnitPrice" :formatter="formattedNumber" />
               <el-table-column label="鍚◣鎬讳环(鍏�)" prop="taxInclusiveTotalPrice" :formatter="formattedNumber" />
@@ -101,6 +81,13 @@
                     @click="openDeliveryForm(scope.row)">
                     鍙戣揣
                   </el-button>
+                  <el-button 
+                    link 
+                    type="primary" 
+                    size="small"
+                    @click="openDeliveryDetail(scope.row)">
+                    璇︽儏
+                  </el-button>
                 </template>
               </el-table-column>
             </el-table>
@@ -110,16 +97,17 @@
         <el-table-column label="閿�鍞悎鍚屽彿" prop="salesContractNo" width="180" show-overflow-tooltip />
         <el-table-column label="瀹㈡埛鍚嶇О" prop="customerName" width="300" show-overflow-tooltip />
         <el-table-column label="涓氬姟鍛�" prop="salesman" width="100" show-overflow-tooltip />
-        <el-table-column label="椤圭洰鍚嶇О" prop="projectName" width="180" show-overflow-tooltip />
-        <el-table-column label="浠樻鏂瑰紡" prop="paymentMethod" show-overflow-tooltip />
+
         <el-table-column label="鍚堝悓閲戦(鍏�)" prop="contractAmount" width="220" show-overflow-tooltip
           :formatter="formattedNumber" />
         <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="openDeliveryForm(scope.row)">鍙戣揣</el-button>-->
@@ -167,25 +155,19 @@
               </el-select>
             </el-form-item>
           </el-col>
-					<el-col :span="12">
+					<!-- <el-col :span="12">
 						<el-form-item label="椤圭洰鍚嶇О锛�" prop="projectName">
 							<el-input v-model="form.projectName" placeholder="璇疯緭鍏�" clearable :disabled="operationType === 'view'" />
 						</el-form-item>
-					</el-col>
-        </el-row>
-        <el-row :gutter="30">
+					</el-col> -->
 					<el-col :span="12">
 						<el-form-item label="绛捐鏃ユ湡锛�" prop="executionDate">
 							<el-date-picker style="width: 100%" v-model="form.executionDate" value-format="YYYY-MM-DD"
 															format="YYYY-MM-DD" type="date" placeholder="璇烽�夋嫨" clearable :disabled="operationType === 'view'" />
 						</el-form-item>
 					</el-col>
-					<el-col :span="12">
-						<el-form-item label="浠樻鏂瑰紡">
-							<el-input v-model="form.paymentMethod" placeholder="璇疯緭鍏�" clearable :disabled="operationType === 'view'" />
-						</el-form-item>
-					</el-col>
-				</el-row>
+        </el-row>
+
 				<el-row :gutter="30">
 					<el-col :span="12">
 						<el-form-item label="褰曞叆浜猴細" prop="entryPerson">
@@ -204,15 +186,24 @@
 						</el-form-item>
 					</el-col>
 				</el-row>
+        <el-row :gutter="30">
+          <el-col :span="12">
+            <el-form-item label="浜よ揣鏃ユ湡锛�" prop="deliveryDate">
+              <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-form-item label="浜у搧淇℃伅锛�">
 						<el-button v-if="operationType !== 'view'" type="primary" @click="openProductForm('add')">娣诲姞</el-button>
 						<el-button v-if="operationType !== 'view'" plain type="danger" @click="deleteProduct" >鍒犻櫎</el-button>
 					</el-form-item>
 				</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" />
@@ -224,20 +215,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 +299,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>
@@ -364,7 +366,7 @@
 						</el-form-item>
 					</el-col>
 					<el-col :span="12">
-						<el-form-item label="鏁伴噺锛�" prop="quantity">
+						<el-form-item label="鏁伴噺" prop="quantity">
 							<el-input-number  :step="0.1" :min="0" v-model="productForm.quantity" placeholder="璇疯緭鍏�" clearable
 																:precision="2"
 																@change="calculateFromQuantity" style="width: 100%" />
@@ -459,7 +461,6 @@
 					<div v-for="(item, index) in printData" :key="index" class="print-page">
 						<div class="delivery-note">
 							<div class="header">
-								<div class="company-name">榧庤瘹鐟炲疄涓氭湁闄愯矗浠诲叕鍙�</div>
 								<div class="document-title">闆跺敭鍙戣揣鍗�</div>
 							</div>
 							
@@ -468,10 +469,6 @@
 									<div>
 										<span class="label">鍙戣揣鏃ユ湡锛�</span>
 										<span class="value">{{ formatDate(item.createTime) }}</span>
-									</div>
-									<div>
-										<span class="label">鍙戣揣杞︾墝鍙凤細</span>
-										<span class="value">{{ item.shippingCarNumber }}</span>
 									</div>
 								</div>
 								<div class="info-row">
@@ -562,19 +559,52 @@
 		>
 			<el-form :model="deliveryForm" label-width="120px" label-position="top" :rules="deliveryRules" ref="deliveryFormRef">
 				<el-row :gutter="30">
-					<el-col :span="24">
+					<!-- <el-col :span="12">
 						<el-form-item label="鍙戣揣绫诲瀷锛�" prop="type">
 							<el-select
 								v-model="deliveryForm.type"
 								placeholder="璇烽�夋嫨鍙戣揣绫诲瀷"
+								disabled
 								style="width: 100%"
 							>
-								<el-option label="璐ц溅" value="璐ц溅" />
 								<el-option label="蹇��" value="蹇��" />
 							</el-select>
 						</el-form-item>
+					</el-col> -->
+      <el-col :span="12">
+						<el-form-item label="寰呭彂璐ф暟閲忥細" prop="remainAmount">
+							<el-input v-model="deliveryForm.remainAmount" disabled placeholder="璇疯緭鍏ュ緟鍙戣揣鏁伴噺"></el-input>
+						</el-form-item>
 					</el-col>
+      <el-col :span="12">
+						<el-form-item label="鍙戣揣妯″紡锛�" prop="deliveryMode">
+							<el-select
+								v-model="deliveryForm.deliveryMode"
+								placeholder="璇烽�夋嫨鍙戣揣妯″紡"
+            style="width: 100%"
+            @change="onDeliveryModeChange"
+							>
+							<el-option label="鍏ㄩ儴" value="鍏ㄩ儴" />
+							<el-option label="閮ㄥ垎" value="閮ㄥ垎" />
+							</el-select>
+						</el-form-item>
+					</el-col>
+      <el-col :span="12">
+        <el-form-item label="鍙戣揣鏁伴噺锛�" prop="partSendAmount">
+          <el-input-number
+            v-model="deliveryForm.partSendAmount"
+            :min="1"
+            :max="deliveryForm.remainAmount"
+            :precision="0"
+            :step="1"
+            :disabled="deliveryForm.deliveryMode === '鍏ㄩ儴'"
+            style="width: 100%"
+            placeholder="璇疯緭鍏ユ湰娆″彂璐ф暟閲�"
+          />
+        </el-form-item>
+      </el-col>
 				</el-row>
+				
 
         <!-- 瀹℃壒浜洪�夋嫨锛堜豢鍗忓悓瀹℃壒閲岀殑瀹℃壒浜鸿妭鐐归�夋嫨锛� -->
         <el-row>
@@ -628,6 +658,48 @@
 				</div>
 			</template>
 		</el-dialog>
+
+		<!-- 鍙戣揣璇︽儏寮规 -->
+		<el-dialog
+			v-model="deliveryDetailVisible"
+			title="鍙戣揣璇︽儏"
+			width="80%"
+			:close-on-click-modal="false"
+			@close="closeDeliveryDetail"
+		>
+			<el-table
+				:data="deliveryDetailTableData"
+				border
+				stripe
+				v-loading="deliveryDetailLoading"
+				height="520px"
+			>
+				<el-table-column align="center" label="搴忓彿" type="index" width="60" />
+				<el-table-column prop="salesContractNo" label="閿�鍞鍗�" width="180" show-overflow-tooltip />
+				<el-table-column prop="shippingNo" label="鍙戣揣璁㈠崟鍙�" width="180" show-overflow-tooltip />
+				<el-table-column prop="customerName" label="瀹㈡埛鍚嶇О" min-width="200" show-overflow-tooltip />
+				<el-table-column prop="status" label="鍙戣揣鐘舵��" min-width="200" show-overflow-tooltip />
+				<el-table-column prop="productName" label="浜у搧鍚嶇О" min-width="160" show-overflow-tooltip />
+				<el-table-column prop="specificationModel" label="瑙勬牸鍨嬪彿" min-width="160" show-overflow-tooltip />
+				<el-table-column prop="type" label="鍙戣揣绫诲瀷" width="100" show-overflow-tooltip />
+				<el-table-column prop="expressCompany" label="蹇�掑叕鍙�" width="140" show-overflow-tooltip />
+				<el-table-column prop="expressNumber" label="蹇�掑崟鍙�" width="160" show-overflow-tooltip />
+				<el-table-column prop="partSendAmount" label="鏈鍙戣揣鏁伴噺" width="120" align="center" />
+			</el-table>
+			<pagination
+				v-show="deliveryDetailPage.total > 0"
+				:total="deliveryDetailPage.total"
+				layout="total, sizes, prev, pager, next, jumper"
+				:page="deliveryDetailPage.current"
+				:limit="deliveryDetailPage.size"
+				@pagination="deliveryDetailPaginationChange"
+			/>
+			<template #footer>
+				<div class="dialog-footer">
+					<el-button @click="closeDeliveryDetail">鍏抽棴</el-button>
+				</div>
+			</template>
+		</el-dialog>
 	</div>
 </template>
 
@@ -635,7 +707,7 @@
 import { getToken } from "@/utils/auth";
 import pagination from "@/components/PIMTable/Pagination.vue";
 import {onMounted, ref, getCurrentInstance} from "vue";
-import { addShippingInfo } from "@/api/salesManagement/deliveryLedger.js";
+import { addShippingInfo, deliveryLedgerListPage } from "@/api/salesManagement/deliveryLedger.js";
 import { ElMessageBox, ElMessage } from "element-plus";
 import { UploadFilled, Download } from "@element-plus/icons-vue";
 import useUserStore from "@/store/modules/user";
@@ -694,6 +766,7 @@
 		customerId: "",
 		entryPerson: "",
 		entryDate: "",
+    deliveryDate: "",
 		maintenanceTime: "",
 		productData: [],
 		executionDate: "",
@@ -703,6 +776,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" }],
 	},
 });
@@ -735,7 +809,6 @@
 		taxInclusiveUnitPrice: [
 			{ required: true, message: "璇疯緭鍏�", trigger: "blur" },
 		],
-		taxRate: [{ required: true, message: "璇烽�夋嫨", trigger: "change" }],
 		taxInclusiveTotalPrice: [
 			{ required: true, message: "璇疯緭鍏�", trigger: "blur" },
 		],
@@ -766,22 +839,122 @@
 	quotationNo: "",
 	customer: "",
 });
+// 鎶ヤ环鍗曞脊妗嗗垎椤�
+const quotationPage = reactive({
+	current: 1,
+	size: 10,
+	total: 0,
+});
 const selectedQuotation = ref(null);
 
 // 鍙戣揣鐩稿叧
 const deliveryFormVisible = ref(false);
+const deliveryDetailVisible = ref(false);
+const deliveryDetailLoading = ref(false);
+const deliveryDetailTableData = ref([]);
+const deliveryDetailSalesLedgerId = ref(null);
+const deliveryDetailPage = reactive({
+	current: 1,
+	size: 10,
+	total: 0,
+});
 const currentDeliveryRow = ref(null);
 const deliveryFormData = reactive({
   deliveryForm: {
-    type: "璐ц溅", // 璐ц溅, 蹇��
+    type: "蹇��", // 璐ц溅, 蹇��
+    remainAmount: 0,
+    deliveryMode: "鍏ㄩ儴", // 鍏ㄩ儴 | 閮ㄥ垎
+    partSendAmount: 0,
   },
   deliveryRules: {
     type: [
       { required: true, message: "璇烽�夋嫨鍙戣揣绫诲瀷", trigger: "change" }
+    ],
+    remainAmount: [
+      {
+        validator: (rule, value, callback) => {
+          const remain = Number(value) || 0;
+          if (remain <= 0) {
+            return callback(new Error("寰呭彂璐ф暟閲忛渶瑕佸ぇ浜�0"));
+          }
+          return callback();
+        },
+        trigger: "change",
+      }
+    ],
+    deliveryMode: [
+      { required: true, message: "璇烽�夋嫨鍙戣揣妯″紡", trigger: "change" }
+    ],
+    partSendAmount: [
+      {
+        validator: (rule, value, callback) => {
+          if (deliveryFormData.deliveryForm.deliveryMode !== "閮ㄥ垎") {
+            return callback();
+          }
+          const max = Number(deliveryFormData.deliveryForm.remainAmount) || 0;
+          const v = Number(value);
+          if (!v || v <= 0) {
+            return callback(new Error("璇疯緭鍏ュ彂璐ф暟閲�"));
+          }
+          if (v > max) {
+            return callback(new Error(`鍙戣揣鏁伴噺涓嶈兘瓒呰繃寰呭彂璐ф暟閲�(${max})`));
+          }
+          return callback();
+        },
+        trigger: "change",
+      }
     ]
   },
 });
 const { deliveryForm, deliveryRules } = toRefs(deliveryFormData);
+
+const onDeliveryModeChange = (val) => {
+  const remain = Number(deliveryForm.value.remainAmount) || 0;
+  if (val === "鍏ㄩ儴") {
+    deliveryForm.value.partSendAmount = remain;
+  } else {
+    let v = Number(deliveryForm.value.partSendAmount) || 0;
+    if (v <= 0 || v > remain) {
+      deliveryForm.value.partSendAmount = remain > 0 ? Math.min(1, remain) : 0;
+    }
+  }
+};
+
+const getDeliveryDetailList = () => {
+	if (!deliveryDetailSalesLedgerId.value) return;
+	deliveryDetailLoading.value = true;
+	return deliveryLedgerListPage({
+		salesLedgerProductId: deliveryDetailSalesLedgerId.value,
+		current: deliveryDetailPage.current,
+		size: deliveryDetailPage.size,
+	}).then((res) => {
+		deliveryDetailTableData.value = res?.data?.records || [];
+		deliveryDetailPage.total = res?.data?.total || 0;
+	}).finally(() => {
+		deliveryDetailLoading.value = false;
+	});
+};
+
+const deliveryDetailPaginationChange = (obj) => {
+	deliveryDetailPage.current = obj.page;
+	deliveryDetailPage.size = obj.limit;
+	getDeliveryDetailList();
+};
+
+const openDeliveryDetail = (row) => {
+	deliveryDetailSalesLedgerId.value = row?.id ?? null;
+	deliveryDetailPage.current = 1;
+	deliveryDetailVisible.value = true;
+	getDeliveryDetailList();
+};
+
+const closeDeliveryDetail = () => {
+	deliveryDetailVisible.value = false;
+	deliveryDetailTableData.value = [];
+	deliveryDetailSalesLedgerId.value = null;
+	deliveryDetailPage.current = 1;
+	deliveryDetailPage.total = 0;
+};
 
 // 鍙戣揣瀹℃壒浜鸿妭鐐癸紙浠垮崗鍚屽鎵� infoFormDia.vue锛�
 const approverNodes = ref([{ id: 1, userId: null }]);
@@ -987,6 +1160,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 +1233,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 +1251,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 +1268,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();
 };
 
 // 閫変腑鎶ヤ环鍗曞悗鍥炲~鍒板彴璐﹁〃鍗�
@@ -1196,6 +1397,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");
@@ -1232,10 +1439,15 @@
 const submitProduct = () => {
 	proxy.$refs["productFormRef"].validate((valid) => {
 		if (valid) {
+			// 濡傛灉閲岄潰鐨勬暟鎹病鏈塼axRate 閭e氨榛樿甯︿笂涓�涓猼axRate 涓虹┖
+			if (!Object.prototype.hasOwnProperty.call(productForm.value, 'taxRate') || productForm.value.taxRate === null || productForm.value.taxRate === undefined) {
+				productForm.value.taxRate = 0;
+			}
 			if (operationType.value === "edit") {
 				submitProductEdit();
 			} else {
 				if(productOperationType.value === "add"){
+					
 					productData.value.push({ ...productForm.value });
 				}else{
 					productData.value[productIndex.value] = { ...productForm.value }
@@ -1262,6 +1474,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 +1556,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: "鍙栨秷",
@@ -1558,7 +1818,6 @@
       <div class="print-page">
         <div class="delivery-note">
           <div class="header">
-            <div class="company-name">榧庤瘹鐟炲疄涓氭湁闄愯矗浠诲叕鍙�</div>
             <div class="document-title">闆跺敭鍙戣揣鍗�</div>
           </div>
           
@@ -1762,13 +2021,15 @@
 	// 璁$畻鍚◣鍗曚环 = 鍚◣鎬讳环 / 鏁伴噺
 	productForm.value.taxInclusiveUnitPrice = (totalPrice / quantity).toFixed(2);
 	
-	// 濡傛灉鏈夌◣鐜囷紝璁$畻涓嶅惈绋庢�讳环
+	// 鏈夌◣鐜囧垯璁$畻涓嶅惈绋庢�讳环锛屽惁鍒欎笉鍚◣鎬讳环 = 鍚◣鎬讳环
 	if (productForm.value.taxRate) {
 		productForm.value.taxExclusiveTotalPrice =
 			proxy.calculateTaxExclusiveTotalPrice(
 				totalPrice,
 				productForm.value.taxRate
 			);
+	} else {
+		productForm.value.taxExclusiveTotalPrice = totalPrice.toFixed(2);
 	}
 	
 	isCalculating.value = false;
@@ -1776,39 +2037,34 @@
 
 // 鏍规嵁涓嶅惈绋庢�讳环璁$畻鍚◣鍗曚环鍜屾暟閲�
 const calculateFromExclusiveTotalPrice = () => {
-	if (!productForm.value.taxRate) {
-		proxy.$modal.msgWarning("璇峰厛閫夋嫨绋庣巼");
-		return;
-	}
 	if (isCalculating.value) return;
 	
 	const exclusiveTotalPrice = parseFloat(productForm.value.taxExclusiveTotalPrice);
 	const quantity = parseFloat(productForm.value.quantity);
-	const taxRate = parseFloat(productForm.value.taxRate);
 	
-	if (!exclusiveTotalPrice || !quantity || quantity <= 0 || !taxRate) {
+	if (!exclusiveTotalPrice || !quantity || quantity <= 0) {
 		return;
 	}
 	
 	isCalculating.value = true;
 	
-	// 鍏堣绠楀惈绋庢�讳环 = 涓嶅惈绋庢�讳环 / (1 - 绋庣巼/100)
-	const taxRateDecimal = taxRate / 100;
-	const inclusiveTotalPrice = exclusiveTotalPrice / (1 - taxRateDecimal);
-	productForm.value.taxInclusiveTotalPrice = inclusiveTotalPrice.toFixed(2);
-	
-	// 璁$畻鍚◣鍗曚环 = 鍚◣鎬讳环 / 鏁伴噺
-	productForm.value.taxInclusiveUnitPrice = (inclusiveTotalPrice / quantity).toFixed(2);
+	if (productForm.value.taxRate) {
+		// 鏈夌◣鐜囷細鍚◣鎬讳环 = 涓嶅惈绋庢�讳环 / (1 - 绋庣巼/100)
+		const taxRateDecimal = parseFloat(productForm.value.taxRate) / 100;
+		const inclusiveTotalPrice = exclusiveTotalPrice / (1 - taxRateDecimal);
+		productForm.value.taxInclusiveTotalPrice = inclusiveTotalPrice.toFixed(2);
+		productForm.value.taxInclusiveUnitPrice = (inclusiveTotalPrice / quantity).toFixed(2);
+	} else {
+		// 鏃犵◣鐜囷細鍚◣鎬讳环 = 涓嶅惈绋庢�讳环
+		productForm.value.taxInclusiveTotalPrice = exclusiveTotalPrice.toFixed(2);
+		productForm.value.taxInclusiveUnitPrice = (exclusiveTotalPrice / quantity).toFixed(2);
+	}
 	
 	isCalculating.value = false;
 };
 
 // 鏍规嵁鏁伴噺鍙樺寲璁$畻鎬讳环
 const calculateFromQuantity = () => {
-	if (!productForm.value.taxRate) {
-		proxy.$modal.msgWarning("璇峰厛閫夋嫨绋庣巼");
-		return;
-	}
 	if (isCalculating.value) return;
 	
 	const quantity = parseFloat(productForm.value.quantity);
@@ -1823,13 +2079,15 @@
 	// 璁$畻鍚◣鎬讳环
 	productForm.value.taxInclusiveTotalPrice = (unitPrice * quantity).toFixed(2);
 	
-	// 濡傛灉鏈夌◣鐜囷紝璁$畻涓嶅惈绋庢�讳环
+	// 鏈夌◣鐜囧垯璁$畻涓嶅惈绋庢�讳环锛屽惁鍒欎笉鍚◣鎬讳环 = 鍚◣鎬讳环
 	if (productForm.value.taxRate) {
 		productForm.value.taxExclusiveTotalPrice =
 			proxy.calculateTaxExclusiveTotalPrice(
 				productForm.value.taxInclusiveTotalPrice,
 				productForm.value.taxRate
 			);
+	} else {
+		productForm.value.taxExclusiveTotalPrice = productForm.value.taxInclusiveTotalPrice;
 	}
 	
 	isCalculating.value = false;
@@ -1837,10 +2095,6 @@
 
 // 鏍规嵁鍚◣鍗曚环鍙樺寲璁$畻鎬讳环
 const calculateFromUnitPrice = () => {
-	if (!productForm.value.taxRate) {
-		proxy.$modal.msgWarning("璇峰厛閫夋嫨绋庣巼");
-		return;
-	}
 	if (isCalculating.value) return;
 	
 	const quantity = parseFloat(productForm.value.quantity);
@@ -1855,13 +2109,15 @@
 	// 璁$畻鍚◣鎬讳环
 	productForm.value.taxInclusiveTotalPrice = (unitPrice * quantity).toFixed(2);
 	
-	// 濡傛灉鏈夌◣鐜囷紝璁$畻涓嶅惈绋庢�讳环
+	// 鏈夌◣鐜囧垯璁$畻涓嶅惈绋庢�讳环锛屽惁鍒欎笉鍚◣鎬讳环 = 鍚◣鎬讳环
 	if (productForm.value.taxRate) {
 		productForm.value.taxExclusiveTotalPrice =
 			proxy.calculateTaxExclusiveTotalPrice(
 				productForm.value.taxInclusiveTotalPrice,
 				productForm.value.taxRate
 			);
+	} else {
+		productForm.value.taxExclusiveTotalPrice = productForm.value.taxInclusiveTotalPrice;
 	}
 	
 	isCalculating.value = false;
@@ -1869,27 +2125,27 @@
 
 // 鏍规嵁绋庣巼鍙樺寲璁$畻涓嶅惈绋庢�讳环
 const calculateFromTaxRate = () => {
-	if (!productForm.value.taxRate) {
-		proxy.$modal.msgWarning("璇峰厛閫夋嫨绋庣巼");
-		return;
-	}
 	if (isCalculating.value) return;
 	
 	const inclusiveTotalPrice = parseFloat(productForm.value.taxInclusiveTotalPrice);
-	const taxRate = parseFloat(productForm.value.taxRate);
 	
-	if (!inclusiveTotalPrice || !taxRate) {
+	if (!inclusiveTotalPrice) {
 		return;
 	}
 	
 	isCalculating.value = true;
 	
-	// 璁$畻涓嶅惈绋庢�讳环
-	productForm.value.taxExclusiveTotalPrice =
-		proxy.calculateTaxExclusiveTotalPrice(
-			inclusiveTotalPrice,
-			taxRate
-		);
+	if (productForm.value.taxRate) {
+		// 鏈夌◣鐜囷細閲嶆柊璁$畻涓嶅惈绋庢�讳环
+		productForm.value.taxExclusiveTotalPrice =
+			proxy.calculateTaxExclusiveTotalPrice(
+				inclusiveTotalPrice,
+				parseFloat(productForm.value.taxRate)
+			);
+	} else {
+		// 鏃犵◣鐜囷細涓嶅惈绋庢�讳环 = 鍚◣鎬讳环
+		productForm.value.taxExclusiveTotalPrice = inclusiveTotalPrice.toFixed(2);
+	}
 	
 	isCalculating.value = false;
 };
@@ -1898,30 +2154,18 @@
  * @param row 琛屾暟鎹�
  */
 const getShippingStatusText = (row) => {
-	// 濡傛灉宸插彂璐э紙鏈夊彂璐ф棩鏈熸垨杞︾墝鍙凤級锛屾樉绀�"宸插彂璐�"
-	if (row.shippingDate || row.shippingCarNumber) {
-		return '宸插彂璐�';
-	}
-	
-	// 鑾峰彇鍙戣揣鐘舵�佸瓧娈�
-	const status = row.shippingStatus;
-	
-	// 濡傛灉鐘舵�佷负绌烘垨鏈畾涔夛紝榛樿涓�"寰呭彂璐�"
-	if (status === null || status === undefined || status === '') {
+	const total = Number(row?.quantity || 0);
+	const shipped = Number(row?.partSendAmount || 0);
+	if (shipped <= 0) {
 		return '寰呭彂璐�';
 	}
-	
-	// 鐘舵�佹槸瀛楃涓�
-	const statusStr = String(status).trim();
-	const statusTextMap = {
-		'寰呭彂璐�': '寰呭彂璐�',
-		'寰呭鏍�': '寰呭鏍�',
-		'瀹℃牳涓�': '瀹℃牳涓�',
-		'瀹℃牳鎷掔粷': '瀹℃牳鎷掔粷',
-		'瀹℃牳閫氳繃': '瀹℃牳閫氳繃',
-		'宸插彂璐�': '宸插彂璐�'
-	};
-	return statusTextMap[statusStr] || '寰呭彂璐�';
+	if (shipped < total) {
+		return '鍙戣揣涓�';
+	}
+	if (shipped >= total && total > 0) {
+		return '宸插彂璐�';
+	}
+	return '寰呭彂璐�';
 };
 
 /**
@@ -1929,30 +2173,24 @@
  * @param row 琛屾暟鎹�
  */
 const getShippingStatusType = (row) => {
-	// 濡傛灉宸插彂璐э紙鏈夊彂璐ф棩鏈熸垨杞︾墝鍙凤級锛屾樉绀虹豢鑹�
-	if (row.shippingDate || row.shippingCarNumber) {
-		return 'success';
-	}
-	
-	// 鑾峰彇鍙戣揣鐘舵�佸瓧娈�
-	const status = row.shippingStatus;
-	
-	// 濡傛灉鐘舵�佷负绌烘垨鏈畾涔夛紝榛樿涓虹伆鑹诧紙寰呭彂璐э級
-	if (status === null || status === undefined || status === '') {
+	const total = Number(row?.quantity || 0);
+	const shipped = Number(row?.partSendAmount || 0);
+	if (shipped <= 0) {
 		return 'info';
 	}
-	
-	// 鐘舵�佹槸瀛楃涓�
-	const statusStr = String(status).trim();
-	const typeTextMap = {
-		'寰呭彂璐�': 'info',
-		'寰呭鏍�': 'info',
-		'瀹℃牳涓�': 'warning',
-		'瀹℃牳鎷掔粷': 'danger',
-		'瀹℃牳閫氳繃': 'success',
-		'宸插彂璐�': 'success'
-	};
-	return typeTextMap[statusStr] || 'info';
+	if (shipped < total) {
+		return 'warning';
+	}
+	if (shipped >= total && total > 0) {
+		return 'success';
+	}
+	return 'info';
+};
+
+const getRemainAmount = (row) => {
+	const total = Number(row?.quantity || 0);
+	const shipped = Number(row?.partSendAmount || 0);
+	return Math.max(0, total - shipped);
 };
 
 /**
@@ -1965,18 +2203,13 @@
 	if (row.approveStatus !== 1) {
 		return false;
 	}
-	
-	// 鑾峰彇鍙戣揣鐘舵��
-	const shippingStatus = row.shippingStatus;
-	
-	// 濡傛灉宸插彂璐э紙鏈夊彂璐ф棩鏈熸垨杞︾墝鍙凤級锛屼笉鑳藉啀娆″彂璐�
-	if (row.shippingDate || row.shippingCarNumber) {
+
+	if (getRemainAmount(row) <= 0) {
 		return false;
 	}
-	
-	// 鍙戣揣鐘舵�佸繀椤绘槸"寰呭彂璐�"鎴�"瀹℃牳鎷掔粷"
-	const statusStr = shippingStatus ? String(shippingStatus).trim() : '';
-	return statusStr === '寰呭彂璐�' || statusStr === '瀹℃牳鎷掔粷';
+
+
+	return true;
 };
 
 /**
@@ -1994,6 +2227,7 @@
 	});
 }
 
+
 // 鎵撳紑鍙戣揣寮规
 const openDeliveryForm = (row) => {
 	// 妫�鏌ユ槸鍚﹀彲浠ュ彂璐�
@@ -2001,10 +2235,15 @@
 		proxy.$modal.msgWarning("鍙湁鍦ㄤ骇鍝佺姸鎬佹槸鍏呰冻锛屽彂璐х姸鎬佹槸寰呭彂璐ф垨瀹℃牳鎷掔粷鐨勬椂鍊欐墠鍙互鍙戣揣");
 		return;
 	}
-	
 	currentDeliveryRow.value = row;
+  const total = Number(row.quantity || 0);
+  const shipped = Number(row.partSendAmount || 0);
+  const remain = Math.max(0, total - shipped);
   deliveryForm.value = {
-    type: "璐ц溅",
+    type: "蹇��",
+    remainAmount: remain,
+    deliveryMode: "鍏ㄩ儴",
+    partSendAmount: remain,
   };
   // 閲嶇疆瀹℃壒浜鸿妭鐐癸紙榛樿涓�涓┖鑺傜偣锛�
   approverNodes.value = [{ id: 1, userId: null }];
@@ -2023,6 +2262,24 @@
         return;
       }
       const approveUserIds = approverNodes.value.map(node => node.userId).join(",");
+      const remain = Number(deliveryForm.value.remainAmount) || 0;
+      if (remain <= 0) {
+        proxy.$modal.msgWarning("寰呭彂璐ф暟閲忎负0锛屾棤娉曞彂璐�");
+        return;
+      }
+      const isAllSend = deliveryForm.value.deliveryMode === "鍏ㄩ儴" ? 1 : 0;
+      let quantityToSend = remain;
+      if (isAllSend === 0) {
+        quantityToSend = Number(deliveryForm.value.partSendAmount) || 0;
+        if (quantityToSend <= 0) {
+          proxy.$modal.msgWarning("璇疯緭鍏ュ彂璐ф暟閲�");
+          return;
+        }
+        if (quantityToSend > remain) {
+          proxy.$modal.msgWarning(`鍙戣揣鏁伴噺涓嶈兘瓒呰繃寰呭彂璐ф暟閲�(${remain})`);
+          return;
+        }
+      }
       // 淇濆瓨褰撳墠灞曞紑鐨勮ID锛屼互渚垮彂璐у悗閲嶆柊鍔犺浇瀛愯〃鏍兼暟鎹�
       const currentExpandedKeys = [...expandedRowKeys.value];
       const salesLedgerId = currentDeliveryRow.value.salesLedgerId;
@@ -2030,6 +2287,8 @@
         salesLedgerId: salesLedgerId,
         salesLedgerProductId: currentDeliveryRow.value.id,
         type: deliveryForm.value.type,
+        isAllSend,
+        partSendAmount: quantityToSend,
 				approveUserIds,
       })
         .then(() => {
@@ -2084,6 +2343,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