From c7aebff7f6184b2d8da2669d2db5656e2bc09ec4 Mon Sep 17 00:00:00 2001
From: gaoluyang <2820782392@qq.com>
Date: 星期二, 21 四月 2026 15:49:45 +0800
Subject: [PATCH] 湟水峡 1.反馈登记删减字段 2.售后服务字段匹配错误问题

---
 src/views/salesManagement/salesLedger/index.vue | 1168 +++++++++++++++++++++++++++++++++++++---------------------
 1 files changed, 741 insertions(+), 427 deletions(-)

diff --git a/src/views/salesManagement/salesLedger/index.vue b/src/views/salesManagement/salesLedger/index.vue
index e46ce5f..382a1cd 100644
--- a/src/views/salesManagement/salesLedger/index.vue
+++ b/src/views/salesManagement/salesLedger/index.vue
@@ -14,6 +14,10 @@
           <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>
         </el-form-item>
@@ -26,7 +30,6 @@
           <el-button type="primary" @click="openForm('add')">
             鏂板鍙拌处
           </el-button>
-          <el-button @click="handleImport">瀵煎叆</el-button>
           <el-button @click="handleOut">瀵煎嚭</el-button>
           <el-button type="danger" plain @click="handleDelete">鍒犻櫎</el-button>
           <el-button type="primary" plain @click="handlePrint">鎵撳嵃</el-button>
@@ -34,7 +37,7 @@
       </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%"
-        :summary-method="summarizeMainTable" @expand-change="expandChange" height="calc(100vh - 21em)">
+        :summary-method="summarizeMainTable" @expand-change="expandChange" height="calc(100vh - 18.5em)">
         <el-table-column align="center" type="selection" width="55" />
         <el-table-column type="expand">
           <template #default="props">
@@ -55,55 +58,63 @@
         <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="approvalStatus" width="100" align="center" show-overflow-tooltip>
+          <template #default="scope">
+            <el-tag :type="getApprovalStatusType(scope.row.approvalStatus)" size="small">
+              {{ approvalStatusText[scope.row.approvalStatus] || '鏈煡鐘舵��' }}
+            </el-tag>
+          </template>
+        </el-table-column>
+        <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="productionStatus" width="100" show-overflow-tooltip >
-					<template #default="scope">
-						<div>
-							<el-tag v-if="scope.row.productionStatus === '宸插畬鎴�'" type="success">宸插畬鎴�</el-tag>
-							<el-tag v-if="scope.row.productionStatus === '鐢熶骇涓�'" type="warning">鐢熶骇涓�</el-tag>
-							<el-tag v-if="scope.row.productionStatus === '鏈紑濮�'" type="danger">鏈紑濮�</el-tag>
-						</div>
-					</template>
-				</el-table-column>
-        <el-table-column label="鍙戣揣杞︾墝" prop="shippingCarNumber" width="120" show-overflow-tooltip>
-          <template #default="scope">
-            <div>
-              <div v-if="scope.row.shippingCarNumber">{{ scope.row.shippingCarNumber }}</div>
-              <el-tag v-else type="warning">鏈彂璐�</el-tag>
-            </div>
-          </template>
-        </el-table-column>
-        <el-table-column label="鍙戣揣鏃ユ湡" prop="shippingDate" width="120" show-overflow-tooltip />
-        <el-table-column label="绛捐鏃ユ湡" prop="executionDate" width="120" show-overflow-tooltip />
         <el-table-column label="褰曞叆鏃ユ湡" prop="entryDate" width="120" show-overflow-tooltip />
-        <el-table-column fixed="right" label="鎿嶄綔" min-width="200" align="center">
+        <el-table-column label="绛捐鏃ユ湡" prop="executionDate" width="120" show-overflow-tooltip />
+        <el-table-column label="鍙戣揣鐘舵��" prop="shippingStatus" 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" @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)"
+              :disabled="scope.row.approvalStatus === 3 && scope.row.entryPerson !== userStore.id"
+            >缂栬緫</el-button>
             <el-button link type="primary" size="small" @click="downLoadFile(scope.row)">闄勪欢</el-button>
-            <el-button v-if="!scope.row.shippingCarNumber" link type="primary" size="small" @click="openDeliveryForm(scope.row)">鍙戣揣</el-button>
+            <el-button
+              link
+              type="primary"
+              size="small"
+              @click="openDeliveryForm(scope.row)"
+              :disabled="scope.row.shippingStatus === '宸插彂璐�'"
+            >
+              鍙戣揣
+            </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>
-    <FormDialog 
-      v-model="dialogFormVisible" 
-      :title="operationType === 'add' ? '鏂板閿�鍞彴璐﹂〉闈�' : '缂栬緫閿�鍞彴璐﹂〉闈�'" 
+    <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 v-if="operationType !== 'view'">
-          <el-col :span="24" style="display:flex; justify-content:flex-end; gap:10px; margin-bottom: 6px;">
-            <el-button type="primary" plain @click="openQuotationDialog">浠庡鎵归�氳繃鐨勬姤浠峰崟瀵煎叆</el-button>
-          </el-col>
-        </el-row>
+				<!-- 鎶ヤ环鍗曞鍏ュ叆鍙o細鏀惧湪琛ㄥ崟椤堕儴锛岄�夋嫨鍚庡弽鏄惧鎴�/涓氬姟鍛樼瓑 -->
+<!--				<el-row v-if="operationType === 'add'" style="margin-bottom: 10px;">-->
+<!--					<el-col :span="24" style="text-align: right;">-->
+<!--						<el-button type="primary" plain @click="openQuotationDialog">-->
+<!--							浠庨攢鍞姤浠峰鍏�-->
+<!--						</el-button>-->
+<!--					</el-col>-->
+<!--				</el-row>-->
         <el-row :gutter="30">
           <el-col :span="12">
             <el-form-item label="閿�鍞悎鍚屽彿锛�" prop="salesContractNo">
@@ -127,7 +138,7 @@
               <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>
@@ -158,7 +169,58 @@
             </el-form-item>
           </el-col>
         </el-row>
-
+        <el-row :gutter="30">
+          <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 :gutter="30">
+          <el-col :span="24">
+            <el-form-item>
+              <template #label>
+                <div style="display: flex; align-items: center; justify-content: space-between; width: 100%;">
+                  <span>瀹℃壒浜洪�夋嫨锛�</span>
+                  <el-button v-if="operationType !== 'view'" type="primary" size="small" @click="addApproverNode" icon="Plus">鏂板鑺傜偣</el-button>
+                </div>
+              </template>
+              <div class="approver-nodes-container">
+                <div
+                  v-for="(node, index) in approverNodes"
+                  :key="node.id"
+                  class="approver-node-item"
+                >
+                  <div class="approver-node-header">
+                    <span class="approver-node-label">瀹℃壒鑺傜偣 {{ index + 1 }}</span>
+                    <el-button
+                      v-if="approverNodes.length > 1 && operationType !== 'view'"
+                      type="danger"
+                      size="small"
+                      text
+                      @click="removeApproverNode(index)"
+                      icon="Delete"
+                    >鍒犻櫎</el-button>
+                  </div>
+                  <el-select
+                    v-model="node.userId"
+                    placeholder="璇烽�夋嫨瀹℃壒浜�"
+                    filterable
+                    style="width: 100%;"
+                    :disabled="operationType === 'view'"
+                  >
+                    <el-option
+                      v-for="user in userList"
+                      :key="user.userId"
+                      :label="user.nickName"
+                      :value="user.userId"
+                    />
+                  </el-select>
+                </div>
+              </div>
+            </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>
@@ -208,71 +270,15 @@
           </el-col>
         </el-row>
       </el-form>
-    </FormDialog>
-
-    <!-- 浠庢姤浠峰崟瀵煎叆锛堜粎瀹℃壒閫氳繃锛� -->
-    <el-dialog
-      v-model="quotationDialogVisible"
-      title="閫夋嫨瀹℃壒閫氳繃鐨勯攢鍞姤浠峰崟"
-      width="80%"
-      :close-on-click-modal="false"
-    >
-      <div style="margin-bottom: 12px; display:flex; gap: 12px; align-items:center;">
-        <el-input
-          v-model="quotationSearchForm.quotationNo"
-          placeholder="璇疯緭鍏ユ姤浠峰崟鍙�"
-          clearable
-          style="max-width: 260px;"
-          @change="fetchQuotationList"
-        />
-        <el-input
-          v-model="quotationSearchForm.customer"
-          placeholder="璇疯緭鍏ュ鎴峰悕绉�"
-          clearable
-          style="max-width: 260px;"
-          @change="fetchQuotationList"
-        />
-        <el-button type="primary" @click="fetchQuotationList">鎼滅储</el-button>
-        <el-button @click="resetQuotationSearch">閲嶇疆</el-button>
-      </div>
-
-      <el-table
-        :data="quotationList"
-        border
-        stripe
-        v-loading="quotationLoading"
-        height="420px"
-      >
-        <el-table-column align="center" label="搴忓彿" type="index" width="60" />
-        <el-table-column prop="quotationNo" label="鎶ヤ环鍗曞彿" width="180" show-overflow-tooltip />
-        <el-table-column prop="customer" label="瀹㈡埛鍚嶇О" min-width="220" show-overflow-tooltip />
-        <el-table-column prop="salesperson" label="涓氬姟鍛�" width="120" show-overflow-tooltip />
-        <el-table-column prop="quotationDate" label="鎶ヤ环鏃ユ湡" width="140" />
-        <el-table-column prop="status" label="瀹℃壒鐘舵��" width="120" align="center" />
-        <el-table-column prop="totalAmount" label="鎶ヤ环閲戦(鍏�)" width="160" align="right">
-          <template #default="scope">
-            {{ Number(scope.row.totalAmount ?? 0).toFixed(2) }}
-          </template>
-        </el-table-column>
-        <el-table-column fixed="right" label="鎿嶄綔" width="120" align="center">
-          <template #default="scope">
-            <el-button type="primary" link @click="applyQuotation(scope.row)">閫夋嫨</el-button>
-          </template>
-        </el-table-column>
-      </el-table>
-
       <template #footer>
-        <el-button @click="quotationDialogVisible = false">鍏抽棴</el-button>
+        <div class="dialog-footer">
+          <el-button type="primary" @click="submitForm">纭</el-button>
+          <el-button @click="closeDia">鍙栨秷</el-button>
+        </div>
       </template>
-    </el-dialog>
-    <FormDialog 
-      v-model="productFormVisible" 
-      :title="productOperationType === 'add' ? '鏂板浜у搧' : '缂栬緫浜у搧'" 
-      :width="'40%'"
-      :operation-type="productOperationType"
-      @close="closeProductDia"
-      @confirm="submitProduct"
-      @cancel="closeProductDia">
+    </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">
         <el-row :gutter="30">
           <el-col :span="24">
@@ -288,7 +294,7 @@
         <el-row :gutter="30">
           <el-col :span="24">
             <el-form-item label="瑙勬牸鍨嬪彿锛�" prop="productModelId">
-              <el-select v-model="productForm.productModelId" placeholder="璇烽�夋嫨" clearable @change="getProductModel" filterable>
+              <el-select v-model="productForm.productModelId" placeholder="璇烽�夋嫨" clearable @change="getProductModel">
                 <el-option v-for="item in modelOptions" :key="item.id" :label="item.model" :value="item.id" />
               </el-select>
             </el-form-item>
@@ -302,17 +308,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" />
@@ -349,7 +357,13 @@
           </el-col>
         </el-row>
       </el-form>
-    </FormDialog>
+      <template #footer>
+        <div class="dialog-footer">
+          <el-button type="primary" @click="submitProduct">纭</el-button>
+          <el-button @click="closeProductDia">鍙栨秷</el-button>
+        </div>
+      </template>
+    </el-dialog>
 		<!-- 鎵撳嵃棰勮寮圭獥 -->
 		<el-dialog
 			v-model="printPreviewVisible"
@@ -373,10 +387,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>
@@ -477,6 +491,21 @@
 			<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="type">
+							<el-select
+								v-model="deliveryForm.type"
+								placeholder="璇烽�夋嫨鍙戣揣绫诲瀷"
+								style="width: 100%"
+								@change="handleShippingTypeChange"
+							>
+								<el-option label="璐ц溅" value="璐ц溅" />
+								<el-option label="蹇��" value="蹇��" />
+							</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%"
@@ -491,7 +520,7 @@
 					</el-col>
 				</el-row>
 				<el-row :gutter="30">
-					<el-col :span="24">
+					<el-col :span="24" v-if="deliveryForm.type === '璐ц溅'">
 						<el-form-item label="鍙戣揣杞︾墝鍙凤細" prop="shippingCarNumber">
 							<el-input
 								v-model="deliveryForm.shippingCarNumber"
@@ -500,7 +529,56 @@
 							/>
 						</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-row :gutter="30" v-if="deliveryForm.type === '蹇��'">
+					<el-col :span="24">
+						<el-form-item label="蹇�掑崟鍙凤細" prop="expressNumber">
+							<el-input
+								v-model="deliveryForm.expressNumber"
+								placeholder="璇疯緭鍏ュ揩閫掑崟鍙�"
+								clearable
+							/>
+						</el-form-item>
+					</el-col>
+				</el-row>
+					<el-row :gutter="30">
+						<el-col :span="24">
+							<el-form-item label="鍙戣揣鍥剧墖锛�">
+								<el-upload
+									v-model:file-list="deliveryFileList"
+									:action="upload.url"
+									multiple
+									ref="deliveryFileUpload"
+									auto-upload
+									:headers="upload.headers"
+									:data="{ type: 9 }"
+									:before-upload="handleDeliveryBeforeUpload"
+									:on-error="handleDeliveryUploadError"
+									:on-success="handleDeliveryUploadSuccess"
+									:on-remove="handleDeliveryRemove"
+									list-type="picture-card"
+									:limit="9"
+									accept="image/png,image/jpeg,image/jpg"
+								>
+									<el-icon class="avatar-uploader-icon"><Plus /></el-icon>
+									<template #tip>
+										<div class="el-upload__tip">
+											鏀寔 jpg銆乯peg銆乸ng 鏍煎紡锛屾渶澶氫笂浼� 9 寮狅紝鍗曞紶澶у皬涓嶈秴杩� 10MB
+										</div>
+									</template>
+								</el-upload>
+							</el-form-item>
+						</el-col>
+					</el-row>
 			</el-form>
 			<template #footer>
 				<div class="dialog-footer">
@@ -509,44 +587,63 @@
 				</div>
 			</template>
 		</el-dialog>
-    <FileListDialog ref="fileListRef" v-model="fileListDialogVisible" />
-    <!-- 瀵煎叆瀵硅瘽妗� -->
-    <el-dialog
-      :title="importUpload.title"
-      v-model="importUpload.open"
-      width="400px"
-      append-to-body
-    >
-      <el-upload
-        ref="importUploadRef"
-        :limit="1"
-        accept=".xlsx, .xls"
-        :headers="importUpload.headers"
-        :action="importUpload.url"
-        :disabled="importUpload.isUploading"
-        :before-upload="importUpload.beforeUpload"
-        :on-progress="importUpload.onProgress"
-        :on-success="importUpload.onSuccess"
-        :on-error="importUpload.onError"
-        :on-change="importUpload.onChange"
-        :auto-upload="false"
-        drag
-      >
-        <el-icon class="el-icon--upload"><UploadFilled /></el-icon>
-        <div class="el-upload__text">灏嗘枃浠舵嫋鍒版澶勶紝鎴�<em>鐐瑰嚮涓婁紶</em></div>
-        <template #tip>
-          <div class="el-upload__tip text-center">
-            <span>浠呭厑璁稿鍏ls銆亁lsx鏍煎紡鏂囦欢銆�</span>
-          </div>
-        </template>
-      </el-upload>
-      <template #footer>
-        <div class="dialog-footer">
-          <el-button type="primary" @click="submitImportFile" :loading="importUpload.isUploading">纭� 瀹�</el-button>
-          <el-button @click="importUpload.open = false">鍙� 娑�</el-button>
-        </div>
-      </template>
-    </el-dialog>
+		<!-- 閿�鍞姤浠峰崟閫夋嫨瀵硅瘽妗� -->
+		<el-dialog
+			v-model="quotationDialogVisible"
+			title="閫夋嫨閿�鍞姤浠峰崟"
+			width="80%"
+			:close-on-click-modal="false"
+			@close="resetQuotationSearch"
+		>
+			<div class="search_form" style="margin-bottom: 15px;">
+				<el-form :model="quotationSearchForm" :inline="true">
+					<el-form-item label="鎶ヤ环鍗曞彿锛�">
+						<el-input v-model="quotationSearchForm.quotationNo" placeholder="璇疯緭鍏�" clearable />
+					</el-form-item>
+					<el-form-item label="瀹㈡埛锛�">
+						<el-input v-model="quotationSearchForm.customer" placeholder="璇疯緭鍏�" clearable />
+					</el-form-item>
+					<el-form-item>
+						<el-button type="primary" @click="fetchQuotationList">鎼滅储</el-button>
+						<el-button @click="resetQuotationSearch">閲嶇疆</el-button>
+					</el-form-item>
+				</el-form>
+			</div>
+			<el-table
+				:data="quotationList"
+				border
+				v-loading="quotationLoading"
+				height="400"
+				style="width: 100%"
+			>
+				<el-table-column align="center" label="搴忓彿" type="index" width="60" />
+				<el-table-column label="鎶ヤ环鍗曞彿" prop="quotationNo"show-overflow-tooltip />
+				<el-table-column label="瀹㈡埛" prop="customer" show-overflow-tooltip />
+				<el-table-column label="涓氬姟鍛�" prop="salesperson" show-overflow-tooltip />
+				<el-table-column label="鎶ヤ环鏃ユ湡" prop="quotationDate" show-overflow-tooltip />
+				<el-table-column label="鐘舵��" prop="status" width="100" align="center">
+					<template #default="scope">
+						<el-tag v-if="scope.row.status === '閫氳繃'" type="success" size="small">宸查�氳繃</el-tag>
+						<el-tag v-else type="info" size="small">{{ scope.row.status }}</el-tag>
+					</template>
+				</el-table-column>
+				<el-table-column label="鎿嶄綔" width="100" align="center" fixed="right">
+					<template #default="scope">
+						<el-button link type="primary" size="small" @click="applyQuotation(scope.row)">閫夋嫨</el-button>
+					</template>
+				</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"
+				style="margin-bottom: 15px;"
+				@pagination="quotationPaginationChange"
+			/>
+		</el-dialog>
+    <FileList ref="fileListRef" />
   </div>
 </template>
 
@@ -556,10 +653,10 @@
 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 { UploadFilled, Plus } from "@element-plus/icons-vue";
 import useUserStore from "@/store/modules/user";
 import { userListNoPage } from "@/api/system/user.js";
-import FileListDialog from '@/components/Dialog/FileListDialog.vue';
+import FileList from '@/views/salesManagement/salesLedger/fileList.vue';
 import FormDialog from '@/components/Dialog/FormDialog.vue';
 import { getQuotationList } from "@/api/salesManagement/salesQuotation.js";
 import {
@@ -573,10 +670,12 @@
 	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";
+import {listCustomerPrivatePool} from "@/api/basicData/customerFile.js";
 
 const userStore = useUserStore();
 const { proxy } = getCurrentInstance();
@@ -595,6 +694,17 @@
 });
 const total = ref(0);
 const fileList = ref([]);
+const deliveryFileList = ref([]);
+
+// 瀹℃壒浜鸿妭鐐癸紙浠块噰璐彴璐﹀鎵逛汉锛�
+const approverNodes = ref([{ id: 1, userId: null }]);
+let nextApproverId = 2;
+const addApproverNode = () => {
+  approverNodes.value.push({ id: nextApproverId++, userId: null });
+};
+const removeApproverNode = (index) => {
+  approverNodes.value.splice(index, 1);
+};
 
 // 鐢ㄦ埛淇℃伅琛ㄥ崟寮规鏁版嵁
 const operationType = ref("");
@@ -603,6 +713,7 @@
   searchForm: {
     customerName: "", // 瀹㈡埛鍚嶇О
     salesContractNo: "", // 閿�鍞悎鍚岀紪鍙�
+    productCategory: "", // 浜у搧澶х被
     entryDate: null, // 褰曞叆鏃ユ湡
     entryDateStart: undefined,
     entryDateEnd: undefined,
@@ -616,6 +727,7 @@
     maintenanceTime: "",
     productData: [],
     executionDate: "",
+    paymentMethod: "",
   },
   rules: {
     salesman: [{ required: true, message: "璇烽�夋嫨", trigger: "change" }],
@@ -623,7 +735,7 @@
     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);
@@ -654,14 +766,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);
@@ -682,8 +794,14 @@
 const quotationLoading = ref(false);
 const quotationList = ref([]);
 const quotationSearchForm = reactive({
-  quotationNo: "",
-  customer: "",
+	quotationNo: "",
+	customer: "",
+});
+// 鎶ヤ环鍗曞脊妗嗗垎椤�
+const quotationPage = reactive({
+	current: 1,
+	size: 10,
+	total: 0,
 });
 const selectedQuotation = ref(null);
 
@@ -692,67 +810,29 @@
 const currentDeliveryRow = ref(null);
 const deliveryFormData = reactive({
   deliveryForm: {
+    type: "璐ц溅", // 璐ц溅, 蹇��
     shippingDate: "",
     shippingCarNumber: "",
+    expressCompany: "",
+    expressNumber: "", // 蹇�掑崟鍙�
+    shippingImages: "", // 鍙戣揣鍥剧墖锛屽涓敤閫楀彿鍒嗛殧
   },
   deliveryRules: {
+    type: [
+      { required: true, message: "璇烽�夋嫨鍙戣揣绫诲瀷", trigger: "change" }
+    ],
     shippingDate: [
       { required: true, message: "璇烽�夋嫨鍙戣揣鏃ユ湡", trigger: "change" }
     ],
     shippingCarNumber: [
-      { required: true, message: "璇疯緭鍏ュ彂璐ц溅鐗屽彿", trigger: "blur" }
+      { validator: (_, value, callback) => validateShippingCarNumber(value, callback), trigger: "blur" }
+    ],
+    expressCompany: [
+      { validator: (_, value, callback) => validateExpressCompany(value, callback), trigger: "blur" }
     ],
   },
 });
 const { deliveryForm, deliveryRules } = toRefs(deliveryFormData);
-
-// 瀵煎叆鐩稿叧
-const importUploadRef = ref(null);
-const importUpload = reactive({
-  title: "瀵煎叆閿�鍞彴璐�",
-  open: false,
-  url: import.meta.env.VITE_APP_BASE_API + "/sales/ledger/import",
-  headers: { Authorization: "Bearer " + getToken() },
-  isUploading: false,
-  beforeUpload: (file) => {
-    const isExcel = file.name.endsWith('.xlsx') || file.name.endsWith('.xls');
-    const isLt10M = file.size / 1024 / 1024 < 10;
-    if (!isExcel) {
-      proxy.$modal.msgError("涓婁紶鏂囦欢鍙兘鏄� xlsx/xls 鏍煎紡!");
-      return false;
-    }
-    if (!isLt10M) {
-      proxy.$modal.msgError("涓婁紶鏂囦欢澶у皬涓嶈兘瓒呰繃 10MB!");
-      return false;
-    }
-    return true;
-  },
-  onChange: (file, fileList) => {
-    console.log('鏂囦欢鐘舵�佹敼鍙�', file, fileList);
-  },
-  onProgress: (event, file, fileList) => {
-    console.log('涓婁紶涓�...', event.percent);
-  },
-  onSuccess: (response, file, fileList) => {
-    console.log('涓婁紶鎴愬姛', response, file, fileList);
-    importUpload.isUploading = false;
-    if (response.code === 200) {
-      proxy.$modal.msgSuccess("瀵煎叆鎴愬姛");
-      importUpload.open = false;
-      if (importUploadRef.value) {
-        importUploadRef.value.clearFiles();
-      }
-      getList();
-    } else {
-      proxy.$modal.msgError(response.msg || "瀵煎叆澶辫触");
-    }
-  },
-  onError: (error, file, fileList) => {
-    console.error('涓婁紶澶辫触', error, file, fileList);
-    importUpload.isUploading = false;
-    proxy.$modal.msgError("瀵煎叆澶辫触锛岃閲嶈瘯");
-  },
-});
 
 const changeDaterange = (value) => {
   if (value) {
@@ -784,11 +864,7 @@
 const getList = () => {
   tableLoading.value = true;
   const { entryDate, ...rest } = searchForm;
-  // 灏嗚寖鍥存棩鏈熷瓧娈典紶閫掔粰鍚庣
-  const params = { ...rest, ...page };
-  // 绉婚櫎褰曞叆鏃ユ湡鐨勯粯璁ゅ�艰缃紝鍙繚鐣欒寖鍥存棩鏈熷瓧娈�
-  delete params.entryDate;
-  ledgerListPage(params)
+  ledgerListPage({ ...rest, ...page })
     .then((res) => {
       tableLoading.value = false;
       tableData.value = res.records;
@@ -805,12 +881,33 @@
 const getProductOptions = () => {
   // 杩斿洖 Promise锛屼究浜庡湪缂栬緫浜у搧鏃剁瓑寰呭姞杞藉畬鎴�
   return productTreeList().then((res) => {
-    productOptions.value = convertIdToValue(res);
+    // 鍏煎鎺ュ彛杩斿洖 { data: [] } 鎴栫洿鎺ヨ繑鍥炴暟缁�
+    const list = Array.isArray(res) ? res : (res?.data ?? []);
+    productOptions.value = convertIdToValue(list);
     return productOptions.value;
   });
 };
 const formattedNumber = (row, column, cellValue) => {
   return parseFloat(cellValue).toFixed(2);
+};
+
+// 璁㈠崟瀹℃壒鐘舵�佹樉绀烘枃鏈�
+const approvalStatusText = {
+  1: "寰呭鏍�",
+  2: "瀹℃壒涓�",
+  3: "瀹℃壒閫氳繃",
+  4: "瀹℃壒澶辫触",
+};
+
+// 鑾峰彇瀹℃壒鐘舵�佹爣绛剧被鍨�
+const getApprovalStatusType = (status) => {
+  const typeMap = {
+    1: "info",      // 寰呭鏍� - 鐏拌壊
+    2: "warning",   // 瀹℃壒涓� - 姗欒壊
+    3: "success",   // 瀹℃壒閫氳繃 - 缁胯壊
+    4: "danger",    // 瀹℃壒澶辫触 - 绾㈣壊
+  };
+  return typeMap[status] || "info";
 };
 // 鑾峰彇tree瀛愭暟鎹�
 const getModels = (value) => {
@@ -820,10 +917,12 @@
   });
 };
 const getProductModel = (value) => {
+  console.log("value", 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;
+    fetchQuotationPrice();
   } else {
     productForm.value.specificationModel = null;
     productForm.value.unit = null;
@@ -842,6 +941,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) => {
@@ -920,18 +1042,20 @@
   operationType.value = type;
   form.value = {};
   productData.value = [];
-  selectedQuotation.value = null;
   let userLists = await userListNoPage();
   userList.value = userLists.data;
-  customerList().then((res) => {
-    customerOption.value = res;
-  });
+	listCustomerPrivatePool({current: -1,size:-1}).then((res) => {
+		customerOption.value = res.data.records;
+	});
   form.value.entryPerson = userStore.id;
   if (type === "add") {
     // 鏂板鏃惰缃綍鍏ユ棩鏈熶负褰撳ぉ
     form.value.entryDate = getCurrentDate();
     // 绛捐鏃ユ湡榛樿涓哄綋澶�
     form.value.executionDate = getCurrentDate();
+    // 鏂板鏃堕噸缃鎵逛汉鑺傜偣
+    approverNodes.value = [{ id: 1, userId: null }];
+    nextApproverId = 2;
   } else {
     currentId.value = row.id;
     getSalesLedgerWithProducts({ id: row.id, type: 1 }).then((res) => {
@@ -939,6 +1063,18 @@
       form.value.entryPerson = Number(res.entryPerson);
       productData.value = form.value.productData;
       fileList.value = form.value.salesLedgerFiles;
+      // 鍥炴樉瀹℃壒浜鸿妭鐐�
+      if (res.approveUserIds) {
+        const userIds = res.approveUserIds.split(",").filter(id => id);
+        approverNodes.value = userIds.map((userId, index) => ({
+          id: index + 1,
+          userId: Number(userId)
+        }));
+        nextApproverId = userIds.length + 1;
+      } else {
+        approverNodes.value = [{ id: 1, userId: null }];
+        nextApproverId = 2;
+      }
     });
   }
   // let userAll = await userStore.getInfo()
@@ -953,83 +1089,99 @@
 
 // 鎵撳紑鎶ヤ环鍗曢�夋嫨寮圭獥锛堜粎瀹℃壒閫氳繃锛�
 const openQuotationDialog = async () => {
-  if (operationType.value === "view") return;
-  quotationDialogVisible.value = true;
-  // 鍏堢‘淇濆鎴峰垪琛ㄥ凡鍔犺浇锛屼究浜庡悗缁洖濉� customerId
-  if (!customerOption.value || customerOption.value.length === 0) {
-    try {
-      const res = await customerList();
-      customerOption.value = res;
-    } catch (e) {
-      // ignore锛屽厑璁哥敤鎴峰悗缁墜鍔ㄩ�夋嫨瀹㈡埛
-    }
-  }
-  await fetchQuotationList();
+	if (operationType.value === "view") return;
+	quotationDialogVisible.value = true;
+	// 鎵撳紑寮圭獥鏃堕噸缃垎椤靛埌绗竴椤�
+	quotationPage.current = 1;
+	// 鍏堢‘淇濆鎴峰垪琛ㄥ凡鍔犺浇锛屼究浜庡悗缁洖濉� customerId
+	if (!customerOption.value || customerOption.value.length === 0) {
+		try {
+			listCustomerPrivatePool({current: -1,size:-1}).then((res) => {
+				customerOption.value = res.data.records;
+			});
+		} catch (e) {
+			// ignore锛屽厑璁哥敤鎴峰悗缁墜鍔ㄩ�夋嫨瀹㈡埛
+		}
+	}
+	await fetchQuotationList();
 };
 
 const fetchQuotationList = async () => {
-  quotationLoading.value = true;
-  try {
-    const params = {
-      // 鍏煎鍚庣鍒嗛〉瀛楁锛氳繖閲屾部鐢ㄦ姤浠烽〉闈㈠凡鏈夊彲鐢ㄧ殑瀛楁鍛藉悕
-      currentPage: 1,
-      pageSize: 100,
-      ...quotationSearchForm,
-      status: "閫氳繃",
-    };
-    const res = await getQuotationList(params);
-    quotationList.value = res?.data?.records || [];
-  } finally {
-    quotationLoading.value = false;
-  }
+	quotationLoading.value = true;
+	try {
+		const params = {
+			// 鍚庣鍒嗛〉瀛楁锛歝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;
+	}
 };
 
 const resetQuotationSearch = async () => {
-  quotationSearchForm.quotationNo = "";
-  quotationSearchForm.customer = "";
-  await fetchQuotationList();
+	quotationSearchForm.quotationNo = "";
+	quotationSearchForm.customer = "";
+	quotationPage.current = 1;
+	await fetchQuotationList();
+};
+
+// 鎶ヤ环鍗曞脊妗嗗垎椤靛垏鎹�
+const quotationPaginationChange = (obj) => {
+	quotationPage.current = obj.page;
+	quotationPage.size = obj.limit;
+	fetchQuotationList();
 };
 
 // 閫変腑鎶ヤ环鍗曞悗鍥炲~鍒板彴璐﹁〃鍗�
 const applyQuotation = (row) => {
-  if (!row) return;
-  selectedQuotation.value = row;
-
-  // 涓氬姟鍛�
-  form.value.salesman = row.salesperson || "";
-
-  // 瀹㈡埛鍚嶇О -> customerId
-  const customer = (customerOption.value || []).find((c) => c.customerName === row.customer);
-  if (customer?.id) {
-    form.value.customerId = customer.id;
-  } else {
-    // 濡傛灉鎵句笉鍒帮紝淇濈暀鍘熷�硷紙鍏佽鐢ㄦ埛鎵嬪姩閫夋嫨/涓嶆墦鏂凡鏈夎緭鍏ワ級
-    form.value.customerId = form.value.customerId || "";
-  }
-
-  // 浜у搧淇℃伅鏄犲皠锛氭姤浠� products -> 鍙拌处 productData
-  const products = Array.isArray(row.products) ? row.products : [];
-  productData.value = products.map((p) => {
-    const quantity = Number(p.quantity ?? 0) || 0;
-    const unitPrice = Number(p.unitPrice ?? 0) || 0;
-    const taxRate = "13"; // 榛樿 13%锛屼究浜庣洿鎺ユ彁浜わ紙濡傞渶鍙湪浜у搧涓嚜琛屼慨鏀癸級
-    const taxInclusiveTotalPrice = (unitPrice * quantity).toFixed(2);
-    const taxExclusiveTotalPrice = proxy.calculateTaxExclusiveTotalPrice(taxInclusiveTotalPrice, taxRate);
-    return {
-      // 鍙拌处瀛楁
-      productCategory: p.product || p.productName || "",
-      specificationModel: p.specification || "",
-      unit: p.unit || "",
-      quantity: quantity,
-      taxRate: taxRate,
-      taxInclusiveUnitPrice: unitPrice.toFixed(2),
-      taxInclusiveTotalPrice: taxInclusiveTotalPrice,
-      taxExclusiveTotalPrice: taxExclusiveTotalPrice,
-      invoiceType: "澧炴櫘绁�",
-    };
-  });
-
-  quotationDialogVisible.value = false;
+	if (!row) return;
+	selectedQuotation.value = row;
+	
+	// 涓氬姟鍛�
+	form.value.salesman = (row.salesperson || "").trim();
+	
+	// 瀹㈡埛鍚嶇О -> customerId
+	const qCustomerName = String(row.customer || "").trim();
+	const customer = (customerOption.value || []).find((c) => {
+		const name = String(c.customerName || "").trim();
+		return name === qCustomerName || name.includes(qCustomerName) || qCustomerName.includes(name);
+	});
+	if (customer?.id) {
+		form.value.customerId = customer.id;
+	} else {
+		// 濡傛灉鎵句笉鍒帮紝淇濈暀鍘熷�硷紙鍏佽鐢ㄦ埛鎵嬪姩閫夋嫨/涓嶆墦鏂凡鏈夎緭鍏ワ級
+		form.value.customerId = form.value.customerId || "";
+	}
+	
+	// 浜у搧淇℃伅鏄犲皠锛氭姤浠� products -> 鍙拌处 productData
+	const products = Array.isArray(row.products) ? row.products : [];
+	productData.value = products.map((p) => {
+		const quantity = Number(p.quantity ?? 0) || 0;
+		const unitPrice = Number(p.unitPrice ?? 0) || 0;
+		const taxRate = "13"; // 榛樿 13%锛屼究浜庣洿鎺ユ彁浜わ紙濡傞渶鍙湪浜у搧涓嚜琛屼慨鏀癸級
+		const taxInclusiveTotalPrice = (unitPrice * quantity).toFixed(2);
+		const taxExclusiveTotalPrice = proxy.calculateTaxExclusiveTotalPrice(taxInclusiveTotalPrice, taxRate);
+		return {
+			// 鍙拌处瀛楁
+			productCategory: p.product || p.productName || "",
+			specificationModel: p.specification || "",
+			unit: p.unit || "",
+			quantity: quantity,
+			taxRate: taxRate,
+			taxInclusiveUnitPrice: unitPrice.toFixed(2),
+			taxInclusiveTotalPrice: taxInclusiveTotalPrice,
+			taxExclusiveTotalPrice: taxExclusiveTotalPrice,
+			invoiceType: "澧炴櫘绁�",
+		};
+	});
+	
+	quotationDialogVisible.value = false;
 };
 function changs(val) {
   console.log(val);
@@ -1070,6 +1222,47 @@
     });
   }
 }
+// 鍙戣揣鍥剧墖涓婁紶鍓嶆牎妫�
+function handleDeliveryBeforeUpload(file) {
+  // 鏍℃鏂囦欢绫诲瀷
+  const isImage = file.type === 'image/png' || file.type === 'image/jpeg' || file.type === 'image/jpg';
+  if (!isImage) {
+    proxy.$modal.msgError("鍙兘涓婁紶 jpg銆乯peg銆乸ng 鏍煎紡鐨勫浘鐗�!");
+    return false;
+  }
+  // 鏍℃鏂囦欢澶у皬
+  const isLt10M = file.size / 1024 / 1024 < 10;
+  if (!isLt10M) {
+    proxy.$modal.msgError("涓婁紶鍥剧墖澶у皬涓嶈兘瓒呰繃 10MB!");
+    return false;
+  }
+  proxy.$modal.loading("姝e湪涓婁紶鍥剧墖锛岃绋嶅��...");
+  return true;
+}
+// 鍙戣揣鍥剧墖涓婁紶澶辫触
+function handleDeliveryUploadError(err) {
+  proxy.$modal.msgError("涓婁紶鍥剧墖澶辫触");
+  proxy.$modal.closeLoading();
+}
+// 鍙戣揣鍥剧墖涓婁紶鎴愬姛鍥炶皟
+function handleDeliveryUploadSuccess(res, file, uploadFiles) {
+  proxy.$modal.closeLoading();
+  if (res.code === 200) {
+    file.tempId = res.data.tempId;
+    proxy.$modal.msgSuccess("涓婁紶鎴愬姛");
+  } else {
+    proxy.$modal.msgError(res.msg);
+    proxy.$refs.deliveryFileUpload.handleRemove(file);
+  }
+}
+// 绉婚櫎鍙戣揣鍥剧墖
+function handleDeliveryRemove(file) {
+  // 浠庢枃浠跺垪琛ㄤ腑绉婚櫎
+  const index = deliveryFileList.value.findIndex(item => item.uid === file.uid);
+  if (index > -1) {
+    deliveryFileList.value.splice(index, 1);
+  }
+}
 // 鎻愪氦琛ㄥ崟
 const submitForm = () => {
   proxy.$refs["formRef"].validate((valid) => {
@@ -1081,12 +1274,21 @@
         proxy.$modal.msgWarning("璇锋坊鍔犱骇鍝佷俊鎭�");
         return;
       }
+      // 鏍¢獙瀹℃壒浜烘槸鍚﹀凡閫夋嫨
+      const hasEmptyApprover = approverNodes.value.some(node => !node.userId);
+      if (hasEmptyApprover) {
+        proxy.$modal.msgWarning("璇烽�夋嫨瀹℃壒浜�");
+        return;
+      }
       let tempFileIds = [];
       if (fileList.value !== null && fileList.value.length > 0) {
         tempFileIds = fileList.value.map((item) => item.tempId);
       }
       form.value.tempFileIds = tempFileIds;
       form.value.type = 1;
+      // 灏嗗鎵逛汉鑺傜偣杞崲涓洪�楀彿鍒嗛殧鐨勫瓧绗︿覆
+      const approveUserIds = approverNodes.value.map(node => node.userId).join(",");
+      form.value.approveUserIds = approveUserIds;
       addOrUpdateSalesLedger(form.value).then((res) => {
         proxy.$modal.msgSuccess("鎻愪氦鎴愬姛");
         closeDia();
@@ -1099,6 +1301,9 @@
 const closeDia = () => {
   proxy.resetForm("formRef");
   dialogFormVisible.value = false;
+  // 閲嶇疆瀹℃壒浜鸿妭鐐�
+  approverNodes.value = [{ id: 1, userId: null }];
+  nextApproverId = 2;
 };
 
 const productIndex = ref(0);
@@ -1107,6 +1312,12 @@
   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;
@@ -1133,6 +1344,7 @@
     }
   }
   productFormVisible.value = true;
+  getProductOptions();
 };
 // 鎻愪氦浜у搧琛ㄥ崟
 const submitProduct = () => {
@@ -1208,21 +1420,6 @@
   proxy.resetForm("productFormRef");
   productFormVisible.value = false;
 };
-// 瀵煎叆
-const handleImport = () => {
-  importUpload.title = "瀵煎叆閿�鍞彴璐�";
-  importUpload.open = true;
-  if (importUploadRef.value) {
-    importUploadRef.value.clearFiles();
-  }
-};
-
-// 鎻愪氦瀵煎叆鏂囦欢
-const submitImportFile = () => {
-  importUpload.isUploading = true;
-  proxy.$refs["importUploadRef"].submit();
-};
-
 // 瀵煎嚭
 const handleOut = () => {
   ElMessageBox.confirm("閫変腑鐨勫唴瀹瑰皢琚鍑猴紝鏄惁纭瀵煎嚭锛�", "瀵煎嚭", {
@@ -1244,6 +1441,14 @@
     ids = selectedRows.value.map((item) => item.id);
   } else {
     proxy.$modal.msgWarning("璇烽�夋嫨鏁版嵁");
+    return;
+  }
+  // 妫�鏌ユ槸鍚︽湁瀹℃牳閫氳繃涓旂淮鎶や汉涓嶆槸褰撳墠鐧诲綍鐢ㄦ埛鐨勬暟鎹�
+  const cannotDeleteRows = selectedRows.value.filter(
+    (item) => item.approvalStatus === 3 && item.entryPerson !== userStore.id
+  );
+  if (cannotDeleteRows.length > 0) {
+    proxy.$modal.msgWarning("瀹℃牳閫氳繃涓旂淮鎶や汉涓嶆槸褰撳墠鐧诲綍鐢ㄦ埛鐨勬暟鎹笉鍙垹闄�");
     return;
   }
   ElMessageBox.confirm("閫変腑鐨勫唴瀹瑰皢琚垹闄わ紝鏄惁纭鍒犻櫎锛�", "瀵煎嚭", {
@@ -1268,7 +1473,7 @@
 		proxy.$modal.msgWarning("璇烽�夋嫨瑕佹墦鍗扮殑鏁版嵁");
 		return;
 	}
-	
+
 	// 鏄剧ず鍔犺浇鐘舵��
 	proxy.$modal.loading("姝e湪鑾峰彇浜у搧鏁版嵁锛岃绋嶅��...");
 	
@@ -1459,7 +1664,7 @@
       <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>
           
@@ -1471,7 +1676,7 @@
               </div>
               <div>
                 <span class="label">瀹㈡埛鍚嶇О锛�</span>
-                <span class="value">${item.customerName || '寮犵埍鏈�'}</span>
+                <span class="value">${item.customerName}</span>
               </div>
             </div>
             <div class="info-row">
@@ -1493,8 +1698,8 @@
                 </tr>
               </thead>
               <tbody>
-                ${item.products && item.products.length > 0 ? 
-                  item.products.map(product => `
+                ${item.products && item.products.length > 0 ?
+			item.products.map(product => `
                     <tr>
                       <td>${product.productCategory || ''}</td>
                       <td>${product.specificationModel || ''}</td>
@@ -1503,7 +1708,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>
@@ -1590,208 +1795,225 @@
 };
 // 璁$畻浜у搧鎬绘暟閲�
 const getTotalQuantity = (products) => {
-  if (!products || products.length === 0) return '0';
-  const total = products.reduce((sum, product) => {
-    return sum + (parseFloat(product.quantity) || 0);
-  }, 0);
-  return total.toFixed(2);
+	if (!products || products.length === 0) return '0';
+	const total = products.reduce((sum, product) => {
+		return sum + (parseFloat(product.quantity) || 0);
+	}, 0);
+	return total.toFixed(2);
 };
 
 // 璁$畻浜у搧鎬婚噾棰�
 const getTotalAmount = (products) => {
-  if (!products || products.length === 0) return '0';
-  const total = products.reduce((sum, product) => {
-    return sum + (parseFloat(product.taxInclusiveTotalPrice) || 0);
-  }, 0);
-  return total.toFixed(2);
+	if (!products || products.length === 0) return '0';
+	const total = products.reduce((sum, product) => {
+		return sum + (parseFloat(product.taxInclusiveTotalPrice) || 0);
+	}, 0);
+	return total.toFixed(2);
 };
 
 // 鐢ㄤ簬鎵撳嵃鐨勮绠楀嚱鏁�
 const getTotalQuantityForPrint = (products) => {
-  if (!products || products.length === 0) return '0';
-  const total = products.reduce((sum, product) => {
-    return sum + (parseFloat(product.quantity) || 0);
-  }, 0);
-  return total.toFixed(2);
+	if (!products || products.length === 0) return '0';
+	const total = products.reduce((sum, product) => {
+		return sum + (parseFloat(product.quantity) || 0);
+	}, 0);
+	return total.toFixed(2);
 };
 
 const getTotalAmountForPrint = (products) => {
-  if (!products || products.length === 0) return '0';
-  const total = products.reduce((sum, product) => {
-    return sum + (parseFloat(product.taxInclusiveTotalPrice) || 0);
-  }, 0);
-  return total.toFixed(2);
+	if (!products || products.length === 0) return '0';
+	const total = products.reduce((sum, product) => {
+		return sum + (parseFloat(product.taxInclusiveTotalPrice) || 0);
+	}, 0);
+	return total.toFixed(2);
+};
+
+// 鍙戣揣绫诲瀷鏍¢獙锛氳揣杞︽椂瑕佹眰杞︾墝锛屽揩閫掓椂瑕佹眰蹇�掑叕鍙�
+const validateShippingCarNumber = (value, callback) => {
+  if (deliveryForm.value.type === "璐ц溅") {
+    if (!value) return callback(new Error("璇疯緭鍏ュ彂璐ц溅鐗屽彿"));
+  }
+  callback();
+};
+const validateExpressCompany = (value, callback) => {
+  if (deliveryForm.value.type === "蹇��") {
+    if (!value) return callback(new Error("璇疯緭鍏ュ揩閫掑叕鍙�"));
+  }
+  callback();
 };
 
 const mathNum = () => {
-  console.log("productForm.value", productForm.value);
-  if (!productForm.value.taxInclusiveUnitPrice) {
-    return;
-  }
-  if (!productForm.value.quantity) {
-    return;
-  }
-  // 鍚◣鎬讳环璁$畻
-  productForm.value.taxInclusiveTotalPrice =
-    proxy.calculateTaxIncludeTotalPrice(
-      productForm.value.taxInclusiveUnitPrice,
-      productForm.value.quantity
-    );
-  if (productForm.value.taxRate) {
-    // 涓嶅惈绋庢�讳环璁$畻
-    productForm.value.taxExclusiveTotalPrice =
-      proxy.calculateTaxExclusiveTotalPrice(
-        productForm.value.taxInclusiveTotalPrice,
-        productForm.value.taxRate
-      );
-  }
+	console.log("productForm.value", productForm.value);
+	if (!productForm.value.taxInclusiveUnitPrice) {
+		return;
+	}
+	if (!productForm.value.quantity) {
+		return;
+	}
+	// 鍚◣鎬讳环璁$畻
+	productForm.value.taxInclusiveTotalPrice =
+		proxy.calculateTaxIncludeTotalPrice(
+			productForm.value.taxInclusiveUnitPrice,
+			productForm.value.quantity
+		);
+	if (productForm.value.taxRate) {
+		// 涓嶅惈绋庢�讳环璁$畻
+		productForm.value.taxExclusiveTotalPrice =
+			proxy.calculateTaxExclusiveTotalPrice(
+				productForm.value.taxInclusiveTotalPrice,
+				productForm.value.taxRate
+			);
+	}
 };
 
 // 鏍规嵁鍚◣鎬讳环璁$畻鍚◣鍗曚环鍜屾暟閲�
 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;
 };
 /**
@@ -1800,38 +2022,43 @@
  * @param row 涓嬭浇鏂囦欢鐨勭浉鍏充俊鎭璞�
  */
 const fileListRef = ref(null)
-const fileListDialogVisible = ref(false)
 const downLoadFile = (row) => {
   getSalesLedgerWithProducts({ id: row.id, type: 1 }).then((res) => {
-    if (fileListRef.value) {
-      fileListRef.value.open(res.salesLedgerFiles)
-      fileListDialogVisible.value = true
-    }
+    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 = {
+    type: "璐ц溅",
+    shippingDate: getCurrentDate(),
+    shippingCarNumber: "",
+    expressCompany: "",
+    expressNumber: "", // 鍒濆鍖栧揩閫掑崟鍙蜂负绌�
+    shippingImages: "", // 鍒濆鍖栧浘鐗囦负绌�
+  };
+  deliveryFileList.value = []; // 鍒濆鍖栨枃浠跺垪琛ㄤ负绌�
+	deliveryFormVisible.value = true;
 };
 
 // 鎻愪氦鍙戣揣琛ㄥ崟
 const submitDelivery = () => {
   proxy.$refs["deliveryFormRef"].validate((valid) => {
     if (valid) {
+      let tempFileIds = [];
+      if (deliveryFileList.value !== null && deliveryFileList.value.length > 0) {
+        tempFileIds = deliveryFileList.value.map((item) => item.tempId);
+      }
       addShippingInfo({
         salesLedgerId: currentDeliveryRow.value.id,
+        type: deliveryForm.value.type,
         shippingDate: deliveryForm.value.shippingDate,
-        shippingCarNumber: deliveryForm.value.shippingCarNumber,
+        shippingCarNumber: deliveryForm.value.type === "璐ц溅" ? deliveryForm.value.shippingCarNumber : "",
+        expressCompany: deliveryForm.value.type === "蹇��" ? deliveryForm.value.expressCompany : "",
+        expressNumber: deliveryForm.value.type === "蹇��" ? deliveryForm.value.expressNumber : "",
+        tempFileIds: tempFileIds,
       })
         .then(() => {
           proxy.$modal.msgSuccess("鍙戣揣鎴愬姛");
@@ -1848,8 +2075,21 @@
 // 鍏抽棴鍙戣揣寮规
 const closeDeliveryDia = () => {
   proxy.resetForm("deliveryFormRef");
+  deliveryFileList.value = []; // 娓呯┖鏂囦欢鍒楄〃
+  deliveryForm.value.shippingImages = ""; // 娓呯┖鍥剧墖
+  deliveryForm.value.expressNumber = ""; // 娓呯┖蹇�掑崟鍙�
   deliveryFormVisible.value = false;
   currentDeliveryRow.value = null;
+};
+
+// 鍙戣揣绫诲瀷鍒囨崲鏃舵竻绌哄搴斿瓧娈�
+const handleShippingTypeChange = (val) => {
+  if (val === "璐ц溅") {
+    deliveryForm.value.expressCompany = "";
+    deliveryForm.value.expressNumber = "";
+  } else {
+    deliveryForm.value.shippingCarNumber = "";
+  }
 };
 
 onMounted(() => {
@@ -1859,17 +2099,33 @@
 
 <style scoped lang="scss">
 .ml-10 {
-  margin-left: 10px;
+	margin-left: 10px;
+}
+
+:deep(.yellow) {
+  background-color: #FAF0DE;
+}
+
+:deep(.pink) {
+  background-color: #FAE1DE;
+}
+
+:deep(.red) {
+  background-color: #FAE1DE;
+}
+
+:deep(.purple){
+  background-color: #F4DEFA;
 }
 
 .table_list {
-  margin-top: unset;
+	margin-top: unset;
 }
 
 .actions {
-  display: flex;
-  justify-content: space-between;
-  margin-bottom: 10px;
+	display: flex;
+	justify-content: space-between;
+	margin-bottom: 10px;
 }
 .print-preview-dialog {
 	.el-dialog__body {
@@ -2037,4 +2293,62 @@
 		page-break-after: avoid;
 	}
 }
+
+// 闅愯棌鍥剧墖涓婁紶缁勪欢鐨勯瑙堟寜閽紙鏀惧ぇ闀滐級
+:deep(.el-upload-list--picture-card .el-upload-list__item-actions) {
+  .el-upload-list__item-preview {
+    display: none;
+  }
+}
+
+// 瀹℃壒浜鸿妭鐐规牱寮�
+.approver-nodes-container {
+  display: flex;
+  flex-wrap: wrap;
+  gap: 16px;
+  padding: 16px;
+  background-color: #f8f9fa;
+  border-radius: 4px;
+  border: 1px solid #e4e7ed;
+}
+
+.approver-node-item {
+  flex: 0 0 calc(33.333% - 12px);
+  min-width: 200px;
+  padding: 12px;
+  background-color: #fff;
+  border-radius: 4px;
+  border: 1px solid #dcdfe6;
+  transition: all 0.3s;
+
+  &:hover {
+    border-color: #409eff;
+    box-shadow: 0 2px 8px rgba(64, 158, 255, 0.1);
+  }
+}
+
+.approver-node-header {
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+  margin-bottom: 8px;
+}
+
+.approver-node-label {
+  font-size: 13px;
+  font-weight: 500;
+  color: #606266;
+}
+
+@media (max-width: 1200px) {
+  .approver-node-item {
+    flex: 0 0 calc(50% - 8px);
+  }
+}
+
+@media (max-width: 768px) {
+  .approver-node-item {
+    flex: 0 0 100%;
+  }
+}
 </style>

--
Gitblit v1.9.3