From c9e78ad7be4006bfd62e728b249e68a7366d2e38 Mon Sep 17 00:00:00 2001
From: gaoluyang <2820782392@qq.com>
Date: 星期三, 21 一月 2026 17:27:18 +0800
Subject: [PATCH] 湟水峡 1.生产报工单价默认值修改 2.车辆管理页面开发和联调 3.生产管理模块修改 4.发货前端页面开发

---
 src/views/salesManagement/salesLedger/index.vue |  614 +++++++++++++++++++++++++++++++++++++++----------------
 1 files changed, 429 insertions(+), 185 deletions(-)

diff --git a/src/views/salesManagement/salesLedger/index.vue b/src/views/salesManagement/salesLedger/index.vue
index 7482d2e..a1bed58 100644
--- a/src/views/salesManagement/salesLedger/index.vue
+++ b/src/views/salesManagement/salesLedger/index.vue
@@ -6,21 +6,17 @@
           <el-input v-model="searchForm.customerName" placeholder="璇疯緭鍏�" clearable prefix-icon="Search"
             @change="handleQuery" />
         </el-form-item>
-        <el-form-item label="瀹㈡埛鍚堝悓鍙凤細">
-          <el-input v-model="searchForm.customerContractNo" placeholder="璇疯緭鍏�" clearable prefix-icon="Search"
-            @change="handleQuery" />
-        </el-form-item>
         <el-form-item label="閿�鍞悎鍚屽彿锛�">
           <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" />
+        </el-form-item>
+        <el-form-item label="浜у搧澶х被锛�">
+          <el-input v-model="searchForm.productCategory" placeholder="璇疯緭鍏�" clearable prefix-icon="Search"
+                    @change="handleQuery" />
         </el-form-item>
         <el-form-item>
           <el-button type="primary" @click="handleQuery"> 鎼滅储 </el-button>
@@ -50,6 +46,15 @@
               <el-table-column label="浜у搧澶х被" prop="productCategory" />
               <el-table-column label="瑙勬牸鍨嬪彿" prop="specificationModel" />
               <el-table-column label="鍗曚綅" prop="unit" />
+              <el-table-column label="浜у搧鐘舵��" width="100px" align="center">
+                <template #default="scope">
+                  <el-tag v-if="scope.row.approveStatus === 0" type="info">鏈嚭搴�</el-tag>
+                  <el-tag v-if="scope.row.approveStatus === 1" type="success">宸插嚭搴�</el-tag>
+                  <el-tag v-if="scope.row.approveStatus === 2" type="warning">瀹℃牳涓�</el-tag>
+                  <el-tag v-if="scope.row.approveStatus === 3" type="success">瀹℃牳鎴愬姛</el-tag>
+                  <el-tag v-if="scope.row.approveStatus === 4" type="danger">瀹℃牳澶辫触</el-tag>
+                </template>
+              </el-table-column>
               <el-table-column label="鏁伴噺" prop="quantity" />
               <el-table-column label="绋庣巼(%)" prop="taxRate" />
               <el-table-column label="鍚◣鍗曚环(鍏�)" prop="taxInclusiveUnitPrice" :formatter="formattedNumber" />
@@ -60,29 +65,35 @@
         </el-table-column>
         <el-table-column align="center" label="搴忓彿" type="index" width="60" />
         <el-table-column label="閿�鍞悎鍚屽彿" prop="salesContractNo" width="180" show-overflow-tooltip />
-        <el-table-column label="瀹㈡埛鍚堝悓鍙�" prop="customerContractNo" 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="shippingCarNumber" width="140" align="center" show-overflow-tooltip />
+        <el-table-column label="鍙戣揣鏃ユ湡" prop="shippingDate" width="140" align="center" show-overflow-tooltip />
         <el-table-column fixed="right" label="鎿嶄綔" min-width="140" align="center">
           <template #default="scope">
-            <el-button link type="primary" size="small" :disabled="scope.row.invoiceTotal>0 || scope.row.entryPersonName !== userStore.nickName" @click="openForm('edit', scope.row)">缂栬緫</el-button>
-<!--            <el-button link type="primary" size="small" @click="openForm('view', scope.row)">璇︽儏</el-button>-->
+            <el-button link type="primary" size="small" @click="openForm('edit', 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>
           </template>
         </el-table-column>
       </el-table>
       <pagination v-show="total > 0" :total="total" layout="total, sizes, prev, pager, next, jumper"
         :page="page.current" :limit="page.size" @pagination="paginationChange" />
     </div>
-    <el-dialog v-model="dialogFormVisible" :title="operationType === 'add' ? '鏂板閿�鍞彴璐﹂〉闈�' : '缂栬緫閿�鍞彴璐﹂〉闈�'" width="70%"
-      @close="closeDia">
+    <FormDialog
+      v-model="dialogFormVisible"
+      :title="operationType === 'add' ? '鏂板閿�鍞彴璐﹂〉闈�' : '缂栬緫閿�鍞彴璐﹂〉闈�'"
+      :width="'70%'"
+      :operation-type="operationType"
+      @close="closeDia"
+      @confirm="submitForm"
+      @cancel="closeDia">
       <el-form :model="form" label-width="140px" label-position="top" :rules="rules" ref="formRef">
         <el-row :gutter="30">
           <el-col :span="12">
@@ -92,7 +103,9 @@
           </el-col>
           <el-col :span="12">
             <el-form-item label="涓氬姟鍛橈細" prop="salesman">
-              <el-select v-model="form.salesman" placeholder="璇烽�夋嫨" clearable :disabled="operationType === 'view'">
+              <el-select v-model="form.salesman"
+												 filterable
+                         :reserve-keyword="false" placeholder="璇烽�夋嫨" clearable :disabled="operationType === 'view'">
                 <el-option v-for="item in userList" :key="item.nickName" :label="item.nickName"
                   :value="item.nickName" />
               </el-select>
@@ -101,26 +114,14 @@
         </el-row>
         <el-row :gutter="30">
           <el-col :span="12">
-            <el-form-item label="瀹㈡埛鍚堝悓鍙凤細" prop="customerContractNo">
-              <el-input v-model="form.customerContractNo" placeholder="璇疯緭鍏�" clearable :disabled="operationType === 'view'"/>
-            </el-form-item>
-          </el-col>
-          <el-col :span="12">
             <el-form-item label="瀹㈡埛鍚嶇О锛�" prop="customerId">
-              <el-select v-model="form.customerId" placeholder="璇烽�夋嫨" clearable :disabled="operationType === 'view'">
+              <el-select v-model="form.customerId" placeholder="璇烽�夋嫨" clearable :disabled="operationType === 'view'" filterable>
                 <el-option v-for="item in customerOption" :key="item.id" :label="item.customerName" :value="item.id">
                   {{
-                    item.customerName + "鈥斺��" + item.taxpayerIdentificationNumber
+                    item.customerName+'-'+item.customerType
                   }}
                 </el-option>
               </el-select>
-            </el-form-item>
-          </el-col>
-        </el-row>
-        <el-row :gutter="30">
-          <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-col :span="12">
@@ -133,7 +134,10 @@
         <el-row :gutter="30">
 					<el-col :span="12">
 						<el-form-item label="褰曞叆浜猴細" prop="entryPerson">
-							<el-select v-model="form.entryPerson" placeholder="璇烽�夋嫨" clearable @change="changs" disabled>
+							<el-select v-model="form.entryPerson"
+												 filterable
+                         default-first-option
+                         :reserve-keyword="false" placeholder="璇烽�夋嫨" clearable @change="changs">
 								<el-option v-for="item in userList" :key="item.userId" :label="item.nickName" :value="item.userId" />
 							</el-select>
 						</el-form-item>
@@ -141,7 +145,7 @@
           <el-col :span="12">
             <el-form-item label="褰曞叆鏃ユ湡锛�" prop="entryDate">
               <el-date-picker style="width: 100%" v-model="form.entryDate" value-format="YYYY-MM-DD" format="YYYY-MM-DD"
-                type="date" placeholder="璇烽�夋嫨" clearable disabled />
+                type="date" placeholder="璇烽�夋嫨" clearable />
             </el-form-item>
           </el-col>
         </el-row>
@@ -207,7 +211,7 @@
           <el-button @click="closeDia">鍙栨秷</el-button>
         </div>
       </template>
-    </el-dialog>
+    </FormDialog>
     <el-dialog v-model="productFormVisible" :title="productOperationType === 'add' ? '鏂板浜у搧' : '缂栬緫浜у搧'" width="40%"
       @close="closeProductDia">
       <el-form :model="productForm" label-width="140px" label-position="top" :rules="productRules" ref="productFormRef">
@@ -239,17 +243,19 @@
           </el-col>
 					<el-col :span="12">
 						<el-form-item label="绋庣巼(%)锛�" prop="taxRate">
-							<el-select v-model="productForm.taxRate" placeholder="璇烽�夋嫨" clearable @change="calculateFromTaxRate">
-								<el-option label="1" value="1" />
-								<el-option label="6" value="6" />
-								<el-option label="13" value="13" />
-							</el-select>
+<!--							<el-select v-model="productForm.taxRate" placeholder="璇烽�夋嫨" clearable @change="calculateFromTaxRate">-->
+<!--								<el-option label="1" value="1" />-->
+<!--								<el-option label="6" value="6" />-->
+<!--								<el-option label="13" value="13" />-->
+<!--							</el-select>-->
+              <el-input-number :step="1" :min="0" v-model="productForm.taxRate" style="width: 100%"
+                               placeholder="璇疯緭鍏�" clearable @change="calculateFromTaxRate" />
 						</el-form-item>
 					</el-col>
         </el-row>
         <el-row :gutter="30">
           <el-col :span="12">
-            <el-form-item label="鍚◣鍗曚环(鍏�)锛�" prop="taxInclusiveUnitPrice">
+            <el-form-item label="鍚◣/涓嶅惈绋庡崟浠�(鍏�)锛�" prop="taxInclusiveUnitPrice">
               <el-input-number :step="0.01" :min="0" v-model="productForm.taxInclusiveUnitPrice" style="width: 100%"
 															 :precision="2"
 															 placeholder="璇疯緭鍏�" clearable @change="calculateFromUnitPrice" />
@@ -316,10 +322,10 @@
 					<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="company-name">闈掓捣婀熸按宄″啘涓氬彂灞曟湁闄愬叕鍙�</div>
 								<div class="document-title">闆跺敭鍙戣揣鍗�</div>
 							</div>
-							
+
 							<div class="info-section">
 								<div class="info-row">
 									<div>
@@ -327,12 +333,15 @@
 										<span class="value">{{ formatDate(item.createTime) }}</span>
 									</div>
 									<div>
-										
-										<span class="label">瀹㈡埛鍚嶇О锛�</span>
-										<span class="value">{{ item.customerName || '寮犵埍鏈�' }}</span>
+										<span class="label">鍙戣揣杞︾墝鍙凤細</span>
+										<span class="value">{{ item.shippingCarNumber }}</span>
 									</div>
 								</div>
 								<div class="info-row">
+									<div>
+										<span class="label">瀹㈡埛鍚嶇О锛�</span>
+										<span class="value">{{ item.customerName || '寮犵埍鏈�' }}</span>
+									</div>
 									<span class="label">鍗曞彿锛�</span>
 									<span class="value">{{ item.salesContractNo }}</span>
 								</div>
@@ -407,6 +416,72 @@
 				</div>
 			</div>
 		</el-dialog>
+		<!-- 鍙戣揣寮规 -->
+		<el-dialog
+			v-model="deliveryFormVisible"
+			title="鍙戣揣淇℃伅"
+			width="40%"
+			@close="closeDeliveryDia"
+		>
+			<el-form :model="deliveryForm" label-width="120px" label-position="top" :rules="deliveryRules" ref="deliveryFormRef">
+				<el-row :gutter="30">
+					<el-col :span="24">
+						<el-form-item label="鍙戣揣绫诲瀷锛�" prop="shippingType">
+							<el-select
+								v-model="deliveryForm.shippingType"
+								placeholder="璇烽�夋嫨鍙戣揣绫诲瀷"
+								style="width: 100%"
+								@change="handleShippingTypeChange"
+							>
+								<el-option label="璐ц溅" value="truck" />
+								<el-option label="蹇��" value="express" />
+							</el-select>
+						</el-form-item>
+					</el-col>
+				</el-row>
+				<el-row :gutter="30">
+					<el-col :span="24">
+						<el-form-item label="鍙戣揣鏃ユ湡锛�" prop="shippingDate">
+							<el-date-picker
+								style="width: 100%"
+								v-model="deliveryForm.shippingDate"
+								value-format="YYYY-MM-DD"
+								format="YYYY-MM-DD"
+								type="date"
+								placeholder="璇烽�夋嫨鍙戣揣鏃ユ湡"
+								clearable
+							/>
+						</el-form-item>
+					</el-col>
+				</el-row>
+				<el-row :gutter="30">
+					<el-col :span="24" v-if="deliveryForm.shippingType === 'truck'">
+						<el-form-item label="鍙戣揣杞︾墝鍙凤細" prop="shippingCarNumber">
+							<el-input
+								v-model="deliveryForm.shippingCarNumber"
+								placeholder="璇疯緭鍏ュ彂璐ц溅鐗屽彿"
+								clearable
+							/>
+						</el-form-item>
+					</el-col>
+					<el-col :span="24" v-else>
+						<el-form-item label="蹇�掑叕鍙革細" prop="expressCompany">
+							<el-input
+								v-model="deliveryForm.expressCompany"
+								placeholder="璇疯緭鍏ュ揩閫掑叕鍙�"
+								clearable
+							/>
+						</el-form-item>
+					</el-col>
+				</el-row>
+			</el-form>
+			<template #footer>
+				<div class="dialog-footer">
+					<el-button type="primary" @click="submitDelivery">纭鍙戣揣</el-button>
+					<el-button @click="closeDeliveryDia">鍙栨秷</el-button>
+				</div>
+			</template>
+		</el-dialog>
     <FileList ref="fileListRef" />
   </div>
 </template>
@@ -414,25 +489,31 @@
 <script setup>
 import { getToken } from "@/utils/auth";
 import pagination from "@/components/PIMTable/Pagination.vue";
-import {onMounted, ref} from "vue";
-import { ElMessageBox } from "element-plus";
+import {onMounted, ref, getCurrentInstance} from "vue";
+import { addShippingInfo } from "@/api/salesManagement/deliveryLedger.js";
+import { ElMessageBox, ElMessage } from "element-plus";
+import { UploadFilled } from "@element-plus/icons-vue";
 import useUserStore from "@/store/modules/user";
 import { userListNoPage } from "@/api/system/user.js";
-import FileList from "./fileList.vue";
+import FileList from '@/views/salesManagement/salesLedger/fileList.vue';
+import FormDialog from '@/components/Dialog/FormDialog.vue';
+import { getQuotationList } from "@/api/salesManagement/salesQuotation.js";
 import {
-  ledgerListPage,
-  productList,
-  customerList,
-  addOrUpdateSalesLedger,
-  getSalesLedgerWithProducts,
-  delLedger,
-  addOrUpdateSalesLedgerProduct,
-  delProduct,
-  delLedgerFile,
+	ledgerListPage,
+	productList,
+	customerList,
+	addOrUpdateSalesLedger,
+	getSalesLedgerWithProducts,
+	delLedger,
+	addOrUpdateSalesLedgerProduct,
+	delProduct,
+	delLedgerFile, getProductInventory,
 } from "@/api/salesManagement/salesLedger.js";
+import { getQuotationDetail } from "@/api/salesManagement/salesQuotation.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";
 
 const userStore = useUserStore();
 const { proxy } = getCurrentInstance();
@@ -458,22 +539,16 @@
 const data = reactive({
   searchForm: {
     customerName: "", // 瀹㈡埛鍚嶇О
-    customerContractNo: "", // 瀹㈡埛鍚堝悓缂栧彿
     salesContractNo: "", // 閿�鍞悎鍚岀紪鍙�
-    projectName: "", // 椤圭洰鍚嶇О
-    entryDate: [
-      dayjs().format("YYYY-MM-DD"),
-      dayjs().add(1, "day").format("YYYY-MM-DD"),
-    ], // 褰曞叆鏃ユ湡
-    entryDateStart: dayjs().format("YYYY-MM-DD"),
-    entryDateEnd: dayjs().add(1, "day").format("YYYY-MM-DD"),
+    productCategory: "", // 浜у搧澶х被
+    entryDate: null, // 褰曞叆鏃ユ湡
+    entryDateStart: undefined,
+    entryDateEnd: undefined,
   },
   form: {
     salesContractNo: "",
     salesman: "",
-    customerContractNo: "",
     customerId: "",
-    projectName: "",
     entryPerson: "",
     entryDate: "",
     maintenanceTime: "",
@@ -483,15 +558,11 @@
   },
   rules: {
     salesman: [{ required: true, message: "璇烽�夋嫨", trigger: "change" }],
-    customerContractNo: [
-      { required: true, message: "璇疯緭鍏�", trigger: "blur" },
-    ],
     customerId: [{ required: true, message: "璇烽�夋嫨", trigger: "change" }],
-    projectName: [{ required: true, message: "璇疯緭鍏�", trigger: "blur" }],
     entryPerson: [{ required: true, message: "璇烽�夋嫨", trigger: "change" }],
     entryDate: [{ required: true, message: "璇烽�夋嫨", trigger: "change" }],
     executionDate: [{ required: true, message: "璇烽�夋嫨", trigger: "change" }],
-  },
+    },
 });
 const { form, rules } = toRefs(data);
 const { form: searchForm } = useFormData(data.searchForm);
@@ -522,14 +593,14 @@
     taxInclusiveUnitPrice: [
       { required: true, message: "璇疯緭鍏�", trigger: "blur" },
     ],
-    taxRate: [{ required: true, message: "璇烽�夋嫨", trigger: "change" }],
+    // taxRate: [{ required: true, message: "璇烽�夋嫨", trigger: "change" }],
     taxInclusiveTotalPrice: [
       { required: true, message: "璇疯緭鍏�", trigger: "blur" },
     ],
     taxExclusiveTotalPrice: [
       { required: true, message: "璇疯緭鍏�", trigger: "blur" },
     ],
-    invoiceType: [{ required: true, message: "璇烽�夋嫨", trigger: "change" }],
+    // invoiceType: [{ required: true, message: "璇烽�夋嫨", trigger: "change" }],
   },
 });
 const { productForm, productRules } = toRefs(productFormData);
@@ -545,6 +616,33 @@
 const printPreviewVisible = ref(false);
 const printData = ref([]);
 
+// 鍙戣揣鐩稿叧
+const deliveryFormVisible = ref(false);
+const currentDeliveryRow = ref(null);
+const deliveryFormData = reactive({
+  deliveryForm: {
+    shippingType: "truck", // truck: 璐ц溅, express: 蹇��
+    shippingDate: "",
+    shippingCarNumber: "",
+    expressCompany: "",
+  },
+  deliveryRules: {
+    shippingType: [
+      { required: true, message: "璇烽�夋嫨鍙戣揣绫诲瀷", trigger: "change" }
+    ],
+    shippingDate: [
+      { required: true, message: "璇烽�夋嫨鍙戣揣鏃ユ湡", trigger: "change" }
+    ],
+    shippingCarNumber: [
+      { validator: (_, value, callback) => validateShippingCarNumber(value, callback), trigger: "blur" }
+    ],
+    expressCompany: [
+      { validator: (_, value, callback) => validateExpressCompany(value, callback), trigger: "blur" }
+    ],
+  },
+});
+const { deliveryForm, deliveryRules } = toRefs(deliveryFormData);
+
 const changeDaterange = (value) => {
   if (value) {
     searchForm.entryDateStart = dayjs(value[0]).format("YYYY-MM-DD");
@@ -559,7 +657,11 @@
 // 鏌ヨ鍒楄〃
 /** 鎼滅储鎸夐挳鎿嶄綔 */
 const handleQuery = () => {
-  page.current = 1;
+  // 鍙湁鍦ㄧ偣鍑绘悳绱㈡寜閽椂鎵嶉噸缃〉鐮佸埌绗竴椤�
+  // 閬垮厤琛ㄥ崟瀛楁change浜嬩欢骞叉壈鍒嗛〉
+  if (arguments.length === 0) {
+    page.current = 1;
+  }
 	expandedRowKeys.value = [];
   getList();
 };
@@ -586,8 +688,12 @@
 };
 // 鑾峰彇浜у搧澶х被tree鏁版嵁
 const getProductOptions = () => {
-  productTreeList().then((res) => {
-    productOptions.value = convertIdToValue(res);
+  // 杩斿洖 Promise锛屼究浜庡湪缂栬緫浜у搧鏃剁瓑寰呭姞杞藉畬鎴�
+  return productTreeList().then((res) => {
+    // 鍏煎鎺ュ彛杩斿洖 { data: [] } 鎴栫洿鎺ヨ繑鍥炴暟缁�
+    const list = Array.isArray(res) ? res : (res?.data ?? []);
+    productOptions.value = convertIdToValue(list);
+    return productOptions.value;
   });
 };
 const formattedNumber = (row, column, cellValue) => {
@@ -606,6 +712,7 @@
   if (index !== -1) {
     productForm.value.specificationModel = modelOptions.value[index].model;
     productForm.value.unit = modelOptions.value[index].unit;
+    fetchQuotationPrice();
   } else {
     productForm.value.specificationModel = null;
     productForm.value.unit = null;
@@ -625,6 +732,29 @@
   }
   return null; // 娌℃湁鎵惧埌鑺傜偣锛岃繑鍥瀗ull
 };
+// 鏍规嵁鎶ヤ环鎺ュ彛鍥炲~鍗曚环
+const fetchQuotationPrice = async () => {
+  // 闇�瑕佸鎴风被鍨嬨�佷骇鍝佸悕绉般�佽鏍�
+  const customer = customerOption.value.find((c) => c.id === form.value.customerId);
+  const customerType = customer?.customerType || customer?.type;
+  const productName = productForm.value.productCategory;
+  const specification = productForm.value.specificationModel;
+
+  try {
+    const { data } = await getQuotationDetail({
+      type: customerType,
+      productName,
+      specification,
+    });
+    const price = data;
+    if (price !== null && price !== undefined) {
+      productForm.value.taxInclusiveUnitPrice = Number(price);
+      mathNum(); // 閲嶆柊璁$畻鎬讳环
+    }
+  } catch (error) {
+    console.error("鑾峰彇鎶ヤ环鍗曚环澶辫触", error);
+  }
+};
 function convertIdToValue(data) {
   return data.map((item) => {
     const { id, children, ...rest } = item;
@@ -638,6 +768,19 @@
 
     return newItem;
   });
+}
+// 鏍规嵁鍚嶇О鍙嶆煡浜у搧澶х被 id锛屼究浜庝粎瀛樺悕绉版椂鐨勫弽鏄�
+function findNodeIdByLabel(nodes, label) {
+  if (!label) return null;
+  for (let i = 0; i < nodes.length; i++) {
+    const node = nodes[i];
+    if (node.label === label) return node.value;
+    if (node.children && node.children.length > 0) {
+      const found = findNodeIdByLabel(node.children, label);
+      if (found !== null && found !== undefined) return found;
+    }
+  }
+  return null;
 }
 // 琛ㄦ牸閫夋嫨鏁版嵁
 const handleSelectionChange = (selection) => {
@@ -695,7 +838,12 @@
     customerOption.value = res;
   });
   form.value.entryPerson = userStore.id;
-  if (type !== "add") {
+  if (type === "add") {
+    // 鏂板鏃惰缃綍鍏ユ棩鏈熶负褰撳ぉ
+    form.value.entryDate = getCurrentDate();
+    // 绛捐鏃ユ湡榛樿涓哄綋澶�
+    form.value.executionDate = getCurrentDate();
+  } else {
     currentId.value = row.id;
     getSalesLedgerWithProducts({ id: row.id, type: 1 }).then((res) => {
       form.value = { ...res };
@@ -785,13 +933,40 @@
 
 const productIndex = ref(0);
 // 鎵撳紑浜у搧寮规
-const openProductForm = (type, row,index) => {
+const openProductForm = async (type, row, index) => {
   productOperationType.value = type;
   productForm.value = {};
   proxy.resetForm("productFormRef");
+  // 鏂板銆佺紪杈戦兘闇�鍏堝姞杞戒骇鍝佹爲锛屽惁鍒� el-tree-select 鏃犳暟鎹�
+  try {
+    await getProductOptions();
+  } catch (e) {
+    console.error("鍔犺浇浜у搧鏍戝け璐�", e);
+  }
   if (type === "edit") {
     productForm.value = { ...row };
     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 (currentModel) {
+          productForm.value.productModelId = currentModel.id;
+        }
+      }
+    } catch (e) {
+      // 鍔犺浇澶辫触鏃朵繚鎸佸彲缂栬緫锛屼笉涓柇寮圭獥
+      console.error("鍔犺浇浜у搧瑙勬牸鍨嬪彿澶辫触", e);
+    }
   }
   productFormVisible.value = true;
   getProductOptions();
@@ -915,25 +1090,25 @@
 		proxy.$modal.msgWarning("璇烽�夋嫨瑕佹墦鍗扮殑鏁版嵁");
 		return;
 	}
-	
+
 	// 鏄剧ず鍔犺浇鐘舵��
 	proxy.$modal.loading("姝e湪鑾峰彇浜у搧鏁版嵁锛岃绋嶅��...");
-	
+
 	try {
 		// 涓烘瘡涓�変腑鐨勯攢鍞彴璐﹁褰曟煡璇㈠搴旂殑浜у搧鏁版嵁
 		const printDataWithProducts = [];
-		
+
 		for (const row of selectedRows.value) {
 			try {
 				// 璋冪敤productList鎺ュ彛鏌ヨ浜у搧鏁版嵁
 				const productRes = await productList({ salesLedgerId: row.id, type: 1 });
-				
+
 				// 灏嗕骇鍝佹暟鎹暣鍚堝埌閿�鍞彴璐﹁褰曚腑
 				const rowWithProducts = {
 					...row,
 					products: productRes.data || []
 				};
-				
+
 				printDataWithProducts.push(rowWithProducts);
 			} catch (error) {
 				console.error(`鑾峰彇閿�鍞彴璐� ${row.id} 鐨勪骇鍝佹暟鎹け璐�:`, error);
@@ -944,11 +1119,11 @@
 				});
 			}
 		}
-		
+
 		printData.value = printDataWithProducts;
 		console.log('鎵撳嵃鏁版嵁锛堝寘鍚骇鍝侊級:', printData.value);
 		printPreviewVisible.value = true;
-		
+
 	} catch (error) {
 		console.error('鑾峰彇浜у搧鏁版嵁澶辫触:', error);
 		proxy.$modal.msgError("鑾峰彇浜у搧鏁版嵁澶辫触锛岃閲嶈瘯");
@@ -960,10 +1135,10 @@
 const executePrint = () => {
 	console.log('寮�濮嬫墽琛屾墦鍗帮紝鏁版嵁鏉℃暟:', printData.value.length);
 	console.log('鎵撳嵃鏁版嵁:', printData.value);
-	
+
 	// 鍒涘缓涓�涓柊鐨勬墦鍗扮獥鍙�
 	const printWindow = window.open('', '_blank', 'width=800,height=600');
-	
+
 	// 鏋勫缓鎵撳嵃鍐呭
 	let printContent = `
     <!DOCTYPE html>
@@ -1099,17 +1274,17 @@
     </head>
     <body>
   `;
-	
+
 	// 涓烘瘡鏉℃暟鎹敓鎴愭墦鍗伴〉闈�
 	printData.value.forEach((item, index) => {
 		printContent += `
       <div class="print-page">
         <div class="delivery-note">
           <div class="header">
-            <div class="company-name">榧庤瘹鐟炲疄涓氭湁闄愯矗浠诲叕鍙�</div>
+            <div class="company-name">闈掓捣婀熸按宄″啘涓氬彂灞曟湁闄愬叕鍙�</div>
             <div class="document-title">闆跺敭鍙戣揣鍗�</div>
           </div>
-          
+
           <div class="info-section">
             <div class="info-row">
               <div>
@@ -1140,7 +1315,7 @@
                 </tr>
               </thead>
               <tbody>
-                ${item.products && item.products.length > 0 ? 
+                ${item.products && item.products.length > 0 ?
                   item.products.map(product => `
                     <tr>
                       <td>${product.productCategory || ''}</td>
@@ -1150,7 +1325,7 @@
                       <td>${product.quantity || '0'}</td>
                       <td>${product.taxInclusiveTotalPrice || '0'}</td>
                     </tr>
-                  `).join('') : 
+                  `).join('') :
                   '<tr><td colspan="6" style="text-align: center; color: #999;">鏆傛棤浜у搧鏁版嵁</td></tr>'
                 }
               </tbody>
@@ -1197,16 +1372,16 @@
       </div>
     `;
 	});
-	
+
 	printContent += `
     </body>
     </html>
   `;
-	
+
 	// 鍐欏叆鍐呭鍒版柊绐楀彛
 	printWindow.document.write(printContent);
 	printWindow.document.close();
-	
+
 	// 绛夊緟鍐呭鍔犺浇瀹屾垚鍚庢墦鍗�
 	printWindow.onload = () => {
 		setTimeout(() => {
@@ -1235,15 +1410,6 @@
 	const seconds = String(date.getSeconds()).padStart(2, "0");
 	return `${year}/${month}/${day} ${hours}:${minutes}:${seconds}`;
 };
-// 鑾峰彇褰撳墠鏃ユ湡骞舵牸寮忓寲涓� YYYY-MM-DD
-function getCurrentDate() {
-  const today = new Date();
-  const year = today.getFullYear();
-  const month = String(today.getMonth() + 1).padStart(2, "0"); // 鏈堜唤浠�0寮�濮�
-  const day = String(today.getDate()).padStart(2, "0");
-  return `${year}-${month}-${day}`;
-}
-
 // 璁$畻浜у搧鎬绘暟閲�
 const getTotalQuantity = (products) => {
   if (!products || products.length === 0) return '0';
@@ -1279,6 +1445,20 @@
   return total.toFixed(2);
 };
 
+// 鍙戣揣绫诲瀷鏍¢獙锛氳揣杞︽椂瑕佹眰杞︾墝锛屽揩閫掓椂瑕佹眰蹇�掑叕鍙�
+const validateShippingCarNumber = (value, callback) => {
+  if (deliveryForm.value.shippingType === "truck") {
+    if (!value) return callback(new Error("璇疯緭鍏ュ彂璐ц溅鐗屽彿"));
+  }
+  callback();
+};
+const validateExpressCompany = (value, callback) => {
+  if (deliveryForm.value.shippingType === "express") {
+    if (!value) return callback(new Error("璇疯緭鍏ュ揩閫掑叕鍙�"));
+  }
+  callback();
+};
+
 const mathNum = () => {
   console.log("productForm.value", productForm.value);
   if (!productForm.value.taxInclusiveUnitPrice) {
@@ -1306,148 +1486,151 @@
 // 鏍规嵁鍚◣鎬讳环璁$畻鍚◣鍗曚环鍜屾暟閲�
 const calculateFromTotalPrice = () => {
   if (isCalculating.value) return;
-  
+
   const totalPrice = parseFloat(productForm.value.taxInclusiveTotalPrice);
   const quantity = parseFloat(productForm.value.quantity);
-  
+  const taxRate = Number(productForm.value.taxRate) || 0;
+
   if (!totalPrice || !quantity || quantity <= 0) {
     return;
   }
-  
+
   isCalculating.value = true;
-  
+
   // 璁$畻鍚◣鍗曚环 = 鍚◣鎬讳环 / 鏁伴噺
   productForm.value.taxInclusiveUnitPrice = (totalPrice / quantity).toFixed(2);
-  
+
   // 濡傛灉鏈夌◣鐜囷紝璁$畻涓嶅惈绋庢�讳环
-  if (productForm.value.taxRate) {
-    productForm.value.taxExclusiveTotalPrice =
+  productForm.value.taxExclusiveTotalPrice =
       proxy.calculateTaxExclusiveTotalPrice(
-        totalPrice,
-        productForm.value.taxRate
+          totalPrice,
+          taxRate
       );
-  }
-  
+
   isCalculating.value = false;
 };
 
 // 鏍规嵁涓嶅惈绋庢�讳环璁$畻鍚◣鍗曚环鍜屾暟閲�
 const calculateFromExclusiveTotalPrice = () => {
-	if (!productForm.value.taxRate) {
-		proxy.$modal.msgWarning("璇峰厛閫夋嫨绋庣巼");
-		return;
-	}
+	// 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) {
+  const taxRate = Number(productForm.value.taxRate) || 0;
+
+  // if (!exclusiveTotalPrice || !quantity || quantity <= 0 || !taxRate) {
+  //   return;
+  // }
+  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);
-  
+
   isCalculating.value = false;
 };
 
 // 鏍规嵁鏁伴噺鍙樺寲璁$畻鎬讳环
 const calculateFromQuantity = () => {
-	if (!productForm.value.taxRate) {
-		proxy.$modal.msgWarning("璇峰厛閫夋嫨绋庣巼");
-		return;
-	}
+	// if (!productForm.value.taxRate) {
+	// 	proxy.$modal.msgWarning("璇峰厛閫夋嫨绋庣巼");
+	// 	return;
+	// }
   if (isCalculating.value) return;
-  
+
   const quantity = parseFloat(productForm.value.quantity);
   const unitPrice = parseFloat(productForm.value.taxInclusiveUnitPrice);
-  
+  const taxRate = Number(productForm.value.taxRate) || 0;
+
   if (!quantity || quantity <= 0 || !unitPrice) {
     return;
   }
-  
+
   isCalculating.value = true;
-  
+
   // 璁$畻鍚◣鎬讳环
   productForm.value.taxInclusiveTotalPrice = (unitPrice * quantity).toFixed(2);
-  
+
   // 濡傛灉鏈夌◣鐜囷紝璁$畻涓嶅惈绋庢�讳环
-  if (productForm.value.taxRate) {
-    productForm.value.taxExclusiveTotalPrice =
+  productForm.value.taxExclusiveTotalPrice =
       proxy.calculateTaxExclusiveTotalPrice(
-        productForm.value.taxInclusiveTotalPrice,
-        productForm.value.taxRate
+          productForm.value.taxInclusiveTotalPrice,
+          taxRate
       );
-  }
-  
+
   isCalculating.value = false;
 };
 
 // 鏍规嵁鍚◣鍗曚环鍙樺寲璁$畻鎬讳环
 const calculateFromUnitPrice = () => {
-	if (!productForm.value.taxRate) {
-		proxy.$modal.msgWarning("璇峰厛閫夋嫨绋庣巼");
-		return;
-	}
+	// if (!productForm.value.taxRate) {
+	// 	proxy.$modal.msgWarning("璇峰厛閫夋嫨绋庣巼");
+	// 	return;
+	// }
   if (isCalculating.value) return;
-  
+
   const quantity = parseFloat(productForm.value.quantity);
   const unitPrice = parseFloat(productForm.value.taxInclusiveUnitPrice);
-  
+  const taxRate = Number(productForm.value.taxRate) || 0;
+
   if (!quantity || quantity <= 0 || !unitPrice) {
     return;
   }
-  
+
   isCalculating.value = true;
-  
+
   // 璁$畻鍚◣鎬讳环
   productForm.value.taxInclusiveTotalPrice = (unitPrice * quantity).toFixed(2);
-  
+
   // 濡傛灉鏈夌◣鐜囷紝璁$畻涓嶅惈绋庢�讳环
-  if (productForm.value.taxRate) {
-    productForm.value.taxExclusiveTotalPrice =
+  productForm.value.taxExclusiveTotalPrice =
       proxy.calculateTaxExclusiveTotalPrice(
-        productForm.value.taxInclusiveTotalPrice,
-        productForm.value.taxRate
+          productForm.value.taxInclusiveTotalPrice,
+          taxRate
       );
-  }
-  
+
   isCalculating.value = false;
 };
 
 // 鏍规嵁绋庣巼鍙樺寲璁$畻涓嶅惈绋庢�讳环
 const calculateFromTaxRate = () => {
-	if (!productForm.value.taxRate) {
-		proxy.$modal.msgWarning("璇峰厛閫夋嫨绋庣巼");
-		return;
-	}
+	// 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) {
+  const taxRate = Number(productForm.value.taxRate) || 0;
+
+  // if (!inclusiveTotalPrice || !taxRate) {
+  //   return;
+  // }
+  if (!inclusiveTotalPrice) {
     return;
   }
-  
+
   isCalculating.value = true;
-  
+
   // 璁$畻涓嶅惈绋庢�讳环
   productForm.value.taxExclusiveTotalPrice =
     proxy.calculateTaxExclusiveTotalPrice(
       inclusiveTotalPrice,
       taxRate
     );
-  
+
   isCalculating.value = false;
 };
 /**
@@ -1460,8 +1643,69 @@
   getSalesLedgerWithProducts({ id: row.id, type: 1 }).then((res) => {
     fileListRef.value.open(res.salesLedgerFiles)
   });
-
 }
+
+// 鎵撳紑鍙戣揣寮规
+const openDeliveryForm = (row) => {
+  // getProductInventory({ salesLedgerId: row.id, type:1 }).then((res) => {
+  //   currentDeliveryRow.value = row;
+  //   deliveryForm.value = {
+  //     shippingDate: getCurrentDate(),
+  //     shippingCarNumber: "",
+  //   };
+  //   deliveryFormVisible.value = true;
+  // }).catch(err => {
+  //   ElMessage.error(err.msg);
+  // });
+	currentDeliveryRow.value = row;
+  deliveryForm.value = {
+    shippingType: "truck",
+    shippingDate: getCurrentDate(),
+    shippingCarNumber: "",
+    expressCompany: "",
+  };
+	deliveryFormVisible.value = true;
+};
+
+// 鎻愪氦鍙戣揣琛ㄥ崟
+const submitDelivery = () => {
+  proxy.$refs["deliveryFormRef"].validate((valid) => {
+    if (valid) {
+      addShippingInfo({
+        salesLedgerId: currentDeliveryRow.value.id,
+        shippingType: deliveryForm.value.shippingType,
+        shippingDate: deliveryForm.value.shippingDate,
+        shippingCarNumber: deliveryForm.value.shippingType === "truck" ? deliveryForm.value.shippingCarNumber : "",
+        expressCompany: deliveryForm.value.shippingType === "express" ? deliveryForm.value.expressCompany : "",
+      })
+        .then(() => {
+          proxy.$modal.msgSuccess("鍙戣揣鎴愬姛");
+          closeDeliveryDia();
+          getList();
+        })
+        .catch(() => {
+          proxy.$modal.msgError("鍙戣揣澶辫触锛岃閲嶈瘯");
+        });
+    }
+  });
+};
+
+// 鍏抽棴鍙戣揣寮规
+const closeDeliveryDia = () => {
+  proxy.resetForm("deliveryFormRef");
+  deliveryFormVisible.value = false;
+  currentDeliveryRow.value = null;
+};
+
+// 鍙戣揣绫诲瀷鍒囨崲鏃舵竻绌哄搴斿瓧娈�
+const handleShippingTypeChange = (val) => {
+  if (val === "truck") {
+    deliveryForm.value.expressCompany = "";
+  } else {
+    deliveryForm.value.shippingCarNumber = "";
+  }
+};
+
 onMounted(() => {
 	getList();
 });
@@ -1494,12 +1738,12 @@
 		padding: 15px;
 		border-bottom: 1px solid #e4e7ed;
 		text-align: center;
-		
+
 		.el-button {
 			margin: 0 10px;
 		}
 	}
-	
+
 	.print-preview-content {
 		padding: 20px;
 		background-color: #f5f5f5;
@@ -1531,13 +1775,13 @@
 .header {
 	text-align: center;
 	margin-bottom: 8px;
-	
+
 	.company-name {
 		font-size: 18px;
 		font-weight: bold;
 		margin-bottom: 4px;
 	}
-	
+
 	.document-title {
 		font-size: 16px;
 		font-weight: bold;
@@ -1549,16 +1793,16 @@
 	display: flex;
 	justify-content: space-between;
 	align-items: center;
-	
+
 	.info-row {
 		line-height: 20px;
-		
+
 		.label {
 			font-weight: bold;
 			width: 60px;
 			font-size: 14px;
 		}
-		
+
 		.value {
 			margin-right: 20px;
 			min-width: 80px;
@@ -1570,12 +1814,12 @@
 .table-section {
 	margin-bottom: 4px;
 	flex: 1;
-	
+
 	.product-table {
 		width: 100%;
 		border-collapse: collapse;
 		border: 1px solid #000;
-		
+
 		th, td {
 			border: 1px solid #000;
 			padding: 6px;
@@ -1583,16 +1827,16 @@
 			font-size: 14px;
 			line-height: 1.4;
 		}
-		
+
 		th {
 			font-weight: bold;
 		}
-		
+
 		.total-label {
 			text-align: right;
 			font-weight: bold;
 		}
-		
+
 		.total-value {
 			font-weight: bold;
 		}
@@ -1605,22 +1849,22 @@
 		margin-bottom: 3px;
 		line-height: 20px;
 		justify-content: space-between;
-		
+
 		.footer-item {
 			display: flex;
 			margin-right: 20px;
-			
+
 			.label {
 				font-weight: bold;
 				width: 80px;
 				font-size: 14px;
 			}
-			
+
 			.value {
 				min-width: 80px;
 				font-size: 14px;
 			}
-			
+
 			&.address-item {
 				.address-value {
 					min-width: 200px;
@@ -1634,7 +1878,7 @@
 	.app-container {
 		display: none;
 	}
-	
+
 	.print-page {
 		box-shadow: none;
 		margin: 0;

--
Gitblit v1.9.3