From 11d7990309ddace2fa600cbeae58e3ab5ac368f9 Mon Sep 17 00:00:00 2001
From: gaoluyang <2820782392@qq.com>
Date: 星期日, 20 九月 2026 19:25:45 +0800
Subject: [PATCH] 新疆-融邦 1. 委外管理:新增合作商档案、委外订单、往来台账三个页面及接口;合作商附件弹框支持直接上传/删除并即时保存。   2. 信托基金与代储台账:客户档案加「信托基金 / 代储金额」并对超限标红提示;销售台账拆「卖油 / 代储」页签,代储走油库+储罐+合同金额,卖油保留产品明细;台账列表加审批状态与超限红字;审批中心显示销售合同号并能下钻台账明细。   3. 储罐号带入库存:储罐信息表单加「是否启用 / 用途 / 租客信息」联动与校验;库存管理、批号明细、入库/出库表单与列表补齐储罐号、油品、物流、过磅等字段展示。   4. 出库即发货与往来备件:出库台账区分「发货单 / 油品出库」两类来源并分别处理详情;新增备件出入库流水页面。   5. 车辆管理与残油联动:新增车辆管理页面;油品出入库表单物流信息顺序调整,车牌/车挂牌号联动只读。   6. 油品出库联动发货台账:发货台账加「发货单号 / 销售合同号」筛选,修复油品出库行批号列取错字段。   7. 采购申请模块:新增采购申请页面及接口。   8. 付款流水组件:抽出公共「付款流水」弹框组件,采购付款分栏、收付款台账与委外往来台账复用。   9. 列调整:收付款台账删除「付款金额 / 退货金额」;委外往来台账删除「回款金额」,并去掉金额列右对齐。

---
 src/views/procurementManagement/purchaseApplication/index.vue                                  | 1087 +++++++++
 src/views/outsourcingManagement/order/index.vue                                                |  952 ++++++++
 src/views/inventoryManagement/stockManagement/OilStockInDialog.vue                             |   56 
 src/views/salesManagement/receiptPaymentLedger/index.vue                                       |   57 
 src/api/outsourcing/order.js                                                                   |   92 
 src/views/basicData/vehicle/index.vue                                                          |  371 +++
 src/views/outsourcingManagement/partner/index.vue                                              |  668 ++++++
 src/views/salesManagement/salesLedger/index.vue                                                |  321 ++
 src/views/officeProcessAutomation/ApproveManage/approve-list/components/ApproveDetailPanel.vue |   51 
 src/views/basicData/tankInfo/index.vue                                                         |  140 +
 src/api/inventoryManagement/stockManage.js                                                     |    9 
 src/views/inventoryManagement/dispatchLog/Record.vue                                           |  361 ++
 src/views/basicData/customerFile/index.vue                                                     |   81 
 src/api/outsourcing/report.js                                                                  |   20 
 src/views/inventoryManagement/stockManagement/index.vue                                        |    2 
 src/api/equipmentManagement/sparePartsRecord.js                                                |   27 
 src/views/inventoryManagement/stockManagement/Record.vue                                       |  201 +
 src/views/inventoryManagement/receiptManagement/Record.vue                                     |  273 ++
 src/components/PaymentRecordDialog/index.vue                                                   |  330 ++
 src/views/salesManagement/deliveryLedger/index.vue                                             |  233 -
 src/views/equipmentManagement/spareParts/index.vue                                             |   87 
 src/views/officeProcessAutomation/ApproveManage/approve-list/index.vue                         |    4 
 src/views/inventoryManagement/issueManagement/index.vue                                        |   48 
 src/views/inventoryManagement/stockManagement/OilStockOutDialog.vue                            |  286 +
 src/views/equipmentManagement/sparePartsRecord/index.vue                                       |  215 +
 src/views/procurementManagement/paymentLedger/index.vue                                        |   74 
 src/api/basicData/vehicle.js                                                                   |   53 
 src/views/officeProcessAutomation/ApproveManage/approve-list/useApproveList.js                 |   46 
 src/views/outsourcingManagement/transactions/index.vue                                         |  255 ++
 src/api/inventoryManagement/stockOut.js                                                        |   18 
 src/views/inventoryManagement/stockManagement/BatchNoQtyDetail.vue                             |   16 
 src/views/officeProcessAutomation/ApproveManage/approve-list/approveListConstants.js           |    1 
 src/api/procurementManagement/purchaseApplication.js                                           |   56 
 src/views/procurementManagement/transferManagement/index.vue                                   |    8 
 src/api/financialManagement/paymentRecord.js                                                   |   38 
 src/api/outsourcing/partner.js                                                                 |   72 
 36 files changed, 6,122 insertions(+), 487 deletions(-)

diff --git a/src/api/basicData/vehicle.js b/src/api/basicData/vehicle.js
new file mode 100644
index 0000000..c0851cd
--- /dev/null
+++ b/src/api/basicData/vehicle.js
@@ -0,0 +1,53 @@
+import request from "@/utils/request";
+
+// 鍒嗛〉鏌ヨ杞﹁締淇℃伅鍒楄〃
+export function listVehicle(query) {
+  return request({
+    url: "/basic/vehicle/list",
+    method: "get",
+    params: query,
+  });
+}
+
+// 鏌ヨ鍏ㄩ儴鍚敤杞﹁締锛堜緵涓嬫媺閫夋嫨锛�
+export function allVehicle() {
+  return request({
+    url: "/basic/vehicle/all",
+    method: "get",
+  });
+}
+
+// 鏌ヨ杞﹁締璇︽儏
+export function getVehicle(id) {
+  return request({
+    url: "/basic/vehicle/" + id,
+    method: "get",
+  });
+}
+
+// 鏂板杞﹁締
+export function addVehicle(data) {
+  return request({
+    url: "/basic/vehicle/add",
+    method: "post",
+    data: data,
+  });
+}
+
+// 淇敼杞﹁締
+export function updateVehicle(data) {
+  return request({
+    url: "/basic/vehicle/update",
+    method: "post",
+    data: data,
+  });
+}
+
+// 鍒犻櫎杞﹁締
+export function delVehicle(ids) {
+  return request({
+    url: "/basic/vehicle/del",
+    method: "delete",
+    data: ids,
+  });
+}
diff --git a/src/api/equipmentManagement/sparePartsRecord.js b/src/api/equipmentManagement/sparePartsRecord.js
new file mode 100644
index 0000000..cdb1411
--- /dev/null
+++ b/src/api/equipmentManagement/sparePartsRecord.js
@@ -0,0 +1,27 @@
+import request from "@/utils/request";
+
+/**
+ * 澶囦欢鍑哄叆搴撴祦姘� - 鍒嗛〉鏌ヨ
+ * params: { current, size, sparePartsId?, direction?, sourceType? }
+ * direction: 1=鍏ュ簱 2=鍑哄簱
+ * sourceType: 1=閲囪喘鍏ュ簱 2=缁翠慨棰嗙敤 3=淇濆吇棰嗙敤
+ */
+export const getSparePartsRecordPage = (params) => {
+  return request({
+    url: "/sparePartsRecord/listPage",
+    method: "get",
+    params,
+  });
+};
+
+/**
+ * 澶囦欢鍑哄叆搴撴祦姘� - 鎵归噺鍒犻櫎锛坆ody 涓� id 鏁扮粍锛�
+ */
+export const delSparePartsRecord = (ids) => {
+  const idList = Array.isArray(ids) ? ids : [ids];
+  return request({
+    url: "/sparePartsRecord/delete",
+    method: "delete",
+    data: idList,
+  });
+};
diff --git a/src/api/financialManagement/paymentRecord.js b/src/api/financialManagement/paymentRecord.js
new file mode 100644
index 0000000..7145918
--- /dev/null
+++ b/src/api/financialManagement/paymentRecord.js
@@ -0,0 +1,38 @@
+import request from "@/utils/request";
+
+/** 浠樻鍥炴娴佹按鍒嗛〉鍒楄〃 */
+export function paymentRecordPage(params) {
+  return request({
+    url: "/paymentRecord/listPage",
+    method: "get",
+    params,
+  });
+}
+
+/** 鏂板浠樻鍥炴娴佹按 */
+export function addPaymentRecord(data) {
+  return request({
+    url: "/paymentRecord/add",
+    method: "post",
+    data,
+  });
+}
+
+/** 淇敼浠樻鍥炴娴佹按 */
+export function updatePaymentRecord(data) {
+  return request({
+    url: "/paymentRecord/update",
+    method: "post",
+    data,
+  });
+}
+
+/** 鍒犻櫎浠樻鍥炴娴佹按锛坆ody 涓� id 鏁扮粍锛� */
+export function delPaymentRecord(ids) {
+  const idList = Array.isArray(ids) ? ids : [ids];
+  return request({
+    url: "/paymentRecord/delete",
+    method: "delete",
+    data: idList,
+  });
+}
diff --git a/src/api/inventoryManagement/stockManage.js b/src/api/inventoryManagement/stockManage.js
index e2a4ebf..1140987 100644
--- a/src/api/inventoryManagement/stockManage.js
+++ b/src/api/inventoryManagement/stockManage.js
@@ -80,4 +80,13 @@
     })
 }
 
+//鍑哄簱绠$悊-鏌ヨ瑙勬牸鍨嬪彿涓嬬殑鍙敤鎵规锛堝彲鐢ㄩ噺 = 搴撳瓨閲� - 閿佸畾鏁伴噺锛�
+export function getBatchNoList(productModelId) {
+    return request({
+        url: '/stockmanagement/batchNoList',
+        method: 'get',
+        params: { productModelId }
+    })
+}
+
 //
\ No newline at end of file
diff --git a/src/api/inventoryManagement/stockOut.js b/src/api/inventoryManagement/stockOut.js
index b54e004..b70b7bc 100644
--- a/src/api/inventoryManagement/stockOut.js
+++ b/src/api/inventoryManagement/stockOut.js
@@ -44,3 +44,21 @@
         data,
     });
 }
+
+// 娌瑰搧鍑哄簱鍙敤閲忔煡璇紙涓婃鍓╀綑娌归噺 + 褰撳墠搴撳瓨锛�
+export const getOilOutAvailableQty = (params) => {
+    return request({
+        url: "/stockOutRecord/oilOutAvailableQty",
+        method: "get",
+        params,
+    });
+}
+
+// 褰曞叆閫佸畬璐у悗鐨勫墿浣欐补閲忥紙鍙洿鏂� residualOil 涓�鍒楋級
+export const updateResidualOil = (id, data) => {
+    return request({
+        url: `/stockOutRecord/${id}/residualOil`,
+        method: "put",
+        data,
+    });
+}
diff --git a/src/api/outsourcing/order.js b/src/api/outsourcing/order.js
new file mode 100644
index 0000000..93e3b20
--- /dev/null
+++ b/src/api/outsourcing/order.js
@@ -0,0 +1,92 @@
+import request from "@/utils/request";
+
+// 濮斿璁㈠崟鍒嗛〉鏌ヨ锛圧uoYi 缁撴瀯锛氶《灞� rows锛�
+export function listOutsourcingOrder(query) {
+  return request({
+    url: "/outsourcing/order/list",
+    method: "get",
+    params: query,
+  });
+}
+
+// 濮斿璁㈠崟璇︽儏锛堝惈 productData 鏄庣粏锛�
+export function getOutsourcingOrder(id) {
+  return request({
+    url: "/outsourcing/order/getById",
+    method: "get",
+    params: { id },
+  });
+}
+
+// 鏂板濮斿璁㈠崟锛堝己鍒惰崏绋匡級
+export function addOutsourcingOrder(data) {
+  return request({
+    url: "/outsourcing/order/add",
+    method: "post",
+    data: data,
+  });
+}
+
+// 淇敼濮斿璁㈠崟锛堜粎鑽夌锛屾槑缁嗗叏閲忔彁浜わ級
+export function editOutsourcingOrder(data) {
+  return request({
+    url: "/outsourcing/order/edit",
+    method: "post",
+    data: data,
+  });
+}
+
+// 鍒犻櫎濮斿璁㈠崟锛堜粎鑽夌锛宐ody 涓� id 鏁扮粍锛�
+export function delOutsourcingOrder(ids) {
+  return request({
+    url: "/outsourcing/order/delete",
+    method: "delete",
+    data: ids,
+  });
+}
+
+// 鎻愪氦锛堣崏绋� -> 宸茬‘璁わ級锛宨d 涓� query 鍙傛暟
+export function submitOutsourcingOrder(id) {
+  return request({
+    url: "/outsourcing/order/submit",
+    method: "post",
+    params: { id },
+  });
+}
+
+// 瀹屾垚锛堝凡纭 -> 宸插畬鎴愶級
+export function completeOutsourcingOrder(id) {
+  return request({
+    url: "/outsourcing/order/complete",
+    method: "post",
+    params: { id },
+  });
+}
+
+// 浣滃簾锛堣崏绋�/宸茬‘璁� -> 宸蹭綔搴燂級
+export function cancelOutsourcingOrder(id, cancelReason) {
+  return request({
+    url: "/outsourcing/order/cancel",
+    method: "post",
+    params: { id, cancelReason },
+  });
+}
+
+// 瀵煎嚭濮斿璁㈠崟锛堣繑鍥� Excel 鏂囦欢娴侊級
+export function exportOutsourcingOrder(query) {
+  return request({
+    url: "/outsourcing/order/export",
+    method: "post",
+    data: query,
+    responseType: "blob",
+  });
+}
+
+// 鎶ュ簾鍝侀�夋枡鍒嗛〉锛堝彧璇伙紝杩斿洖 IPage锛歞ata.records锛�
+export function scrapStockPage(query) {
+  return request({
+    url: "/outsourcing/order/scrapStockPage",
+    method: "get",
+    params: query,
+  });
+}
diff --git a/src/api/outsourcing/partner.js b/src/api/outsourcing/partner.js
new file mode 100644
index 0000000..07feabd
--- /dev/null
+++ b/src/api/outsourcing/partner.js
@@ -0,0 +1,72 @@
+import request from "@/utils/request";
+
+// 鍚堜綔鍟嗘。妗堝垎椤垫煡璇紙杩斿洖 IPage锛歞ata.records锛�
+export function listPartner(query) {
+  return request({
+    url: "/outsourcing/partner/listPage",
+    method: "get",
+    params: query,
+  });
+}
+
+// 鍚堜綔鍟嗘。妗堣鎯咃紙鍚� storageBlobVOS 闄勪欢鍥炴樉锛�
+export function getPartner(id) {
+  return request({
+    url: "/outsourcing/partner/" + id,
+    method: "get",
+  });
+}
+
+// 鏂板鍚堜綔鍟�
+export function addPartner(data) {
+  return request({
+    url: "/outsourcing/partner/add",
+    method: "post",
+    data: data,
+  });
+}
+
+// 淇敼鍚堜綔鍟嗭紙storageBlobDTOS 涓哄叏閲忚鐩栵級
+export function updatePartner(data) {
+  return request({
+    url: "/outsourcing/partner/update",
+    method: "post",
+    data: data,
+  });
+}
+
+// 鍒犻櫎鍚堜綔鍟嗭紙body 涓� id 鏁扮粍锛�
+export function delPartner(ids) {
+  return request({
+    url: "/outsourcing/partner/del",
+    method: "delete",
+    data: ids,
+  });
+}
+
+// 瀵煎嚭鍚堜綔鍟嗭紙杩斿洖 Excel 鏂囦欢娴侊級
+export function exportPartner(query) {
+  return request({
+    url: "/outsourcing/partner/export",
+    method: "post",
+    data: query,
+    responseType: "blob",
+  });
+}
+
+// 涓嬭浇瀵煎叆妯℃澘锛堣繑鍥� Excel 鏂囦欢娴侊級
+export function downloadPartnerTemplate() {
+  return request({
+    url: "/outsourcing/partner/downloadTemplate",
+    method: "post",
+    responseType: "blob",
+  });
+}
+
+// 鍚堜綔鍟嗕笅鎷夐�夐」锛堜粎 id + partnerName锛�
+export function getPartnerOptions() {
+  return request({
+    url: "/outsourcing/partner/getOptions",
+    method: "get",
+  });
+}
diff --git a/src/api/outsourcing/report.js b/src/api/outsourcing/report.js
new file mode 100644
index 0000000..70aa71b
--- /dev/null
+++ b/src/api/outsourcing/report.js
@@ -0,0 +1,20 @@
+import request from "@/utils/request";
+
+// 鍚堜綔鍟嗗線鏉ユ眹鎬伙紙杩斿洖 IPage锛歞ata.records锛�
+export function partnerTransactions(query) {
+  return request({
+    url: "/outsourcing/report/partnerTransactions",
+    method: "get",
+    params: query,
+  });
+}
+
+// 鍚堜綔鍟嗗線鏉ユ槑缁嗭紙閫愯鍗曪紝杩斿洖 IPage锛歞ata.records锛�
+// 娉ㄦ剰锛氭瘡琛� paidAmount 鏄悎浣滃晢绾у悎璁★紝涓嶆槸璁㈠崟绾�
+export function partnerTransactionsDetails(partnerId) {
+  return request({
+    url: "/outsourcing/report/partnerTransactionsDetails",
+    method: "get",
+    params: { partnerId },
+  });
+}
diff --git a/src/api/procurementManagement/purchaseApplication.js b/src/api/procurementManagement/purchaseApplication.js
new file mode 100644
index 0000000..b43df27
--- /dev/null
+++ b/src/api/procurementManagement/purchaseApplication.js
@@ -0,0 +1,56 @@
+// 閲囪喘鐢宠椤甸潰鎺ュ彛
+import request from "@/utils/request";
+
+// 鍒嗛〉鏌ヨ閲囪喘鐢宠鍒楄〃
+export function applicationList(query) {
+  return request({
+    url: "/purchase/application/list",
+    method: "get",
+    params: query,
+  });
+}
+
+// 鏌ヨ閲囪喘鐢宠璇︽儏锛堝惈浜у搧鏄庣粏锛�
+export function getApplicationById(query) {
+  return request({
+    url: "/purchase/application/getById",
+    method: "get",
+    params: query,
+  });
+}
+
+// 鏂板閲囪喘鐢宠锛堣崏绋匡級
+export function addApplication(data) {
+  return request({
+    url: "/purchase/application/add",
+    method: "post",
+    data: data,
+  });
+}
+
+// 淇敼閲囪喘鐢宠
+export function editApplication(data) {
+  return request({
+    url: "/purchase/application/edit",
+    method: "post",
+    data: data,
+  });
+}
+
+// 鍒犻櫎閲囪喘鐢宠锛堟敮鎸佹壒閲忥級
+export function delApplication(ids) {
+  return request({
+    url: "/purchase/application/delete",
+    method: "delete",
+    data: ids,
+  });
+}
+
+// 閲囪喘鐢宠杞鍗曪紝杩斿洖鐢熸垚鐨勯噰璐彴璐d
+export function convertToOrder(id) {
+  return request({
+    url: "/purchase/application/convertToOrder",
+    method: "post",
+    params: { id },
+  });
+}
diff --git a/src/components/PaymentRecordDialog/index.vue b/src/components/PaymentRecordDialog/index.vue
new file mode 100644
index 0000000..3804394
--- /dev/null
+++ b/src/components/PaymentRecordDialog/index.vue
@@ -0,0 +1,330 @@
+<template>
+  <el-dialog :model-value="visible"
+             :title="title"
+             width="60%"
+             :close-on-click-modal="false"
+             @update:model-value="handleVisibleChange"
+             @close="closeDialog">
+    <div class="payment-record-dialog">
+      <div class="dialog-header">
+        <span class="party-name">{{ partyName }}</span>
+        <el-button type="primary"
+                   @click="openAddForm">鏂板</el-button>
+      </div>
+      <el-table :data="tableData"
+                border
+                v-loading="tableLoading"
+                height="380px">
+        <el-table-column align="center"
+                         label="搴忓彿"
+                         type="index"
+                         width="60" />
+        <el-table-column label="鍙戠敓鏃ユ湡"
+                         prop="recordDate"
+                         width="130"
+                         show-overflow-tooltip />
+        <el-table-column label="閲戦(鍏�)"
+                         prop="amount"
+                         width="140"
+                         show-overflow-tooltip>
+          <template #default="{ row }">
+            {{ formatAmount(row.amount) }}
+          </template>
+        </el-table-column>
+        <el-table-column label="鏂瑰紡"
+                         prop="paymentMethod"
+                         width="140"
+                         show-overflow-tooltip />
+        <el-table-column label="澶囨敞"
+                         prop="remark"
+                         show-overflow-tooltip />
+        <el-table-column label="鎿嶄綔"
+                         align="center"
+                         width="140"
+                         fixed="right">
+          <template #default="{ row }">
+            <el-button link
+                       type="primary"
+                       @click="openEditForm(row)">缂栬緫</el-button>
+            <el-button link
+                       type="danger"
+                       @click="handleDelete(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="formVisible"
+               :title="form.id ? '缂栬緫娴佹按' : '鏂板娴佹按'"
+               width="500px"
+               append-to-body
+               :close-on-click-modal="false"
+               @close="resetForm">
+      <el-form :model="form"
+               label-width="100px"
+               :rules="rules"
+               ref="formRef">
+        <el-form-item label="鍙戠敓鏃ユ湡"
+                      prop="recordDate">
+          <el-date-picker v-model="form.recordDate"
+                          type="date"
+                          value-format="YYYY-MM-DD"
+                          format="YYYY-MM-DD"
+                          placeholder="璇烽�夋嫨"
+                          style="width: 100%" />
+        </el-form-item>
+        <el-form-item label="閲戦(鍏�)"
+                      prop="amount">
+          <el-input-number v-model="form.amount"
+                           :min="0"
+                           :precision="2"
+                           :step="0.01"
+                           placeholder="璇疯緭鍏�"
+                           style="width: 100%" />
+        </el-form-item>
+        <el-form-item label="鏂瑰紡"
+                      prop="paymentMethod">
+          <el-input v-model="form.paymentMethod"
+                    placeholder="璇疯緭鍏�"
+                    clearable />
+        </el-form-item>
+        <el-form-item label="澶囨敞"
+                      prop="remark">
+          <el-input v-model="form.remark"
+                    type="textarea"
+                    :rows="3"
+                    placeholder="璇疯緭鍏�"
+                    clearable />
+        </el-form-item>
+      </el-form>
+      <template #footer>
+        <div class="dialog-footer">
+          <el-button type="primary"
+                     @click="submitForm">纭</el-button>
+          <el-button @click="formVisible = false">鍙栨秷</el-button>
+        </div>
+      </template>
+    </el-dialog>
+  </el-dialog>
+</template>
+
+<script setup>
+  import { ref, reactive, watch, getCurrentInstance } from "vue";
+  import { ElMessageBox } from "element-plus";
+  import pagination from "@/components/PIMTable/Pagination.vue";
+  import {
+    paymentRecordPage,
+    addPaymentRecord,
+    updatePaymentRecord,
+    delPaymentRecord,
+  } from "@/api/financialManagement/paymentRecord.js";
+
+  const props = defineProps({
+    visible: {
+      type: Boolean,
+      default: false,
+    },
+    title: {
+      type: String,
+      default: "鏀朵粯娆炬祦姘�",
+    },
+    // 1=瀹㈡埛锛�2=渚涘簲鍟�
+    partyType: {
+      type: [String, Number],
+      required: true,
+    },
+    partyId: {
+      type: [String, Number],
+      default: "",
+    },
+    partyName: {
+      type: String,
+      default: "",
+    },
+    // 1=浠樻锛�2=鍥炴
+    direction: {
+      type: [String, Number],
+      required: true,
+    },
+  });
+
+  const emit = defineEmits(["update:visible", "changed"]);
+
+  const { proxy } = getCurrentInstance();
+
+  const tableData = ref([]);
+  const tableLoading = ref(false);
+  const total = ref(0);
+  const page = reactive({
+    current: 1,
+    size: 10,
+  });
+
+  const formVisible = ref(false);
+  const formRef = ref(null);
+  const form = ref(buildEmptyForm());
+  const rules = {
+    recordDate: [{ required: true, message: "璇烽�夋嫨鍙戠敓鏃ユ湡", trigger: "change" }],
+    amount: [{ required: true, message: "璇疯緭鍏ラ噾棰�", trigger: "blur" }],
+  };
+
+  function buildEmptyForm() {
+    return {
+      id: "",
+      recordDate: "",
+      amount: undefined,
+      paymentMethod: "",
+      remark: "",
+    };
+  }
+
+  const formatAmount = amount => {
+    return amount ? parseFloat(amount).toFixed(2) : "0.00";
+  };
+
+  const handleVisibleChange = val => {
+    emit("update:visible", val);
+  };
+
+  const closeDialog = () => {
+    page.current = 1;
+    tableData.value = [];
+    total.value = 0;
+    formVisible.value = false;
+  };
+
+  const getList = () => {
+    if (!props.partyId) {
+      tableData.value = [];
+      total.value = 0;
+      return;
+    }
+    tableLoading.value = true;
+    paymentRecordPage({
+      pageNum: page.current,
+      pageSize: page.size,
+      partyType: props.partyType,
+      partyId: props.partyId,
+      direction: props.direction,
+    })
+      .then(res => {
+        tableLoading.value = false;
+        const result = res.data || {};
+        tableData.value = result.records || [];
+        total.value = result.total || 0;
+      })
+      .catch(() => {
+        tableLoading.value = false;
+      });
+  };
+
+  const paginationChange = obj => {
+    page.current = obj.page;
+    page.size = obj.limit;
+    getList();
+  };
+
+  const openAddForm = () => {
+    form.value = buildEmptyForm();
+    formVisible.value = true;
+  };
+
+  const openEditForm = row => {
+    form.value = {
+      id: row.id,
+      recordDate: row.recordDate || "",
+      amount: row.amount === null || row.amount === undefined ? undefined : Number(row.amount),
+      paymentMethod: row.paymentMethod || "",
+      remark: row.remark || "",
+    };
+    formVisible.value = true;
+  };
+
+  const resetForm = () => {
+    formRef.value?.resetFields();
+    form.value = buildEmptyForm();
+  };
+
+  const submitForm = () => {
+    formRef.value?.validate(valid => {
+      if (!valid) {
+        return;
+      }
+      const payload = {
+        partyType: props.partyType,
+        partyId: props.partyId,
+        direction: props.direction,
+        amount: form.value.amount,
+        recordDate: form.value.recordDate || null,
+        paymentMethod: form.value.paymentMethod,
+        remark: form.value.remark,
+      };
+      const isEdit = !!form.value.id;
+      const submitRequest = isEdit
+        ? updatePaymentRecord({ ...payload, id: form.value.id })
+        : addPaymentRecord(payload);
+      submitRequest.then(() => {
+        proxy.$modal.msgSuccess(isEdit ? "淇敼鎴愬姛" : "鏂板鎴愬姛");
+        formVisible.value = false;
+        getList();
+        emit("changed");
+      });
+    });
+  };
+
+  const handleDelete = row => {
+    // 璇ユ帴鍙e悗绔棤褰掑睘鏍¢獙锛屼换浣曠櫥褰曠敤鎴峰彲鍒犱换鎰忔祦姘达紝鏁呯‘璁ゆ甯︿笂鏃ユ湡閲戦瀹氫綅
+    ElMessageBox.confirm(
+      `纭畾鍒犻櫎銆�${row.recordDate || "鏈~鏃ユ湡"} / ${formatAmount(row.amount)} 鍏冦�嶈繖鏉℃祦姘村悧锛熷垹闄ゅ悗涓嶅彲鎭㈠銆俙,
+      "鍒犻櫎娴佹按",
+      {
+        confirmButtonText: "纭",
+        cancelButtonText: "鍙栨秷",
+        type: "warning",
+      }
+    )
+      .then(() => {
+        delPaymentRecord([row.id]).then(() => {
+          proxy.$modal.msgSuccess("鍒犻櫎鎴愬姛");
+          getList();
+          emit("changed");
+        });
+      })
+      .catch(() => {
+        proxy.$modal.msg("宸插彇娑�");
+      });
+  };
+
+  watch(
+    () => props.visible,
+    val => {
+      if (val) {
+        page.current = 1;
+        getList();
+      }
+    }
+  );
+</script>
+
+<style scoped lang="scss">
+  .payment-record-dialog {
+    .dialog-header {
+      display: flex;
+      justify-content: space-between;
+      align-items: center;
+      margin-bottom: 12px;
+
+      .party-name {
+        font-size: 15px;
+        font-weight: 600;
+        color: #303133;
+      }
+    }
+  }
+</style>
diff --git a/src/views/basicData/customerFile/index.vue b/src/views/basicData/customerFile/index.vue
index d300494..562720d 100644
--- a/src/views/basicData/customerFile/index.vue
+++ b/src/views/basicData/customerFile/index.vue
@@ -48,7 +48,16 @@
                 :isSelection="true"
                 @selection-change="handleSelectionChange"
                 :tableLoading="tableLoading"
-                @pagination="pagination"></PIMTable>
+                @pagination="pagination">
+        <template #depositAmountSlot="{ row }">
+          <el-tooltip v-if="row.exceedsTrustFund"
+                      :content="`浠e偍閲戦鍚堣宸茶秴鍑鸿瀹㈡埛淇℃墭鍩洪噾锛堜俊鎵樺熀閲戯細${row.trustFund}锛塦"
+                      placement="top">
+            <el-text type="danger">{{ formatAmount(row.depositTotalAmount) }}</el-text>
+          </el-tooltip>
+          <span v-else>{{ formatAmount(row.depositTotalAmount) }}</span>
+        </template>
+      </PIMTable>
     </div>
     <el-dialog v-model="dialogFormVisible"
                :title="operationType === 'add' ? '鏂板瀹㈡埛淇℃伅' : '缂栬緫瀹㈡埛淇℃伅'"
@@ -133,6 +142,19 @@
                            :label="dict.label"
                            :value="dict.value" />
               </el-select>
+            </el-form-item>
+          </el-col>
+        </el-row>
+        <el-row :gutter="30">
+          <el-col :span="12">
+            <el-form-item label="淇℃墭鍩洪噾(鍏�)锛�"
+                          prop="trustFund">
+              <el-input-number v-model="form.trustFund"
+                               :min="0"
+                               :precision="2"
+                               :controls="false"
+                               placeholder="璇疯緭鍏ワ紝鍙负绌�"
+                               style="width: 100%" />
             </el-form-item>
           </el-col>
         </el-row>
@@ -461,6 +483,32 @@
               </div>
             </el-col>
           </el-row>
+          <el-row :gutter="20">
+            <el-col :span="12">
+              <div class="info-item">
+                <span class="info-label">淇℃墭鍩洪噾(鍏�)锛�</span>
+                <span class="info-value">{{ formatAmount(detailForm.trustFund) }}</span>
+              </div>
+            </el-col>
+            <el-col :span="12">
+              <div class="info-item">
+                <span class="info-label">浠e偍閲戦(鍏�)锛�</span>
+                <span class="info-value"
+                      :class="{ 'text-danger': detailForm.exceedsTrustFund }">
+                  {{ formatAmount(detailForm.depositTotalAmount) }}
+                </span>
+              </div>
+            </el-col>
+          </el-row>
+          <el-row v-if="detailForm.exceedsTrustFund"
+                  :gutter="20">
+            <el-col :span="24">
+              <el-alert type="warning"
+                        show-icon
+                        :closable="false"
+                        :title="`璇ュ鎴蜂唬鍌ㄩ噾棰濆悎璁� ${formatAmount(detailForm.depositTotalAmount)} 鍏冿紝宸茶秴鍑轰俊鎵樺熀閲� ${formatAmount(detailForm.trustFund)} 鍏僠" />
+            </el-col>
+          </el-row>
         </div>
       </div>
       <!-- 娲借皥杩涘害璁板綍 -->
@@ -675,6 +723,11 @@
     content: [{ required: true, message: "璇疯緭鍏ュ唴瀹�", trigger: "blur" }],
   };
 
+  const formatAmount = value => {
+    return value === null || value === undefined || value === ""
+      ? "-"
+      : Number(value).toFixed(2);
+  };
   // 璇︽儏鐩稿叧
   const detailDialogVisible = ref(false);
   const detailForm = reactive({
@@ -690,6 +743,9 @@
     contactPhone: "",
     maintainer: "",
     maintenanceTime: "",
+    trustFund: "",
+    depositTotalAmount: "",
+    exceedsTrustFund: false,
   });
   const negotiationRecords = ref([]);
 
@@ -759,6 +815,22 @@
       label: "閾惰璐﹀彿",
       prop: "bankAccount",
       width: 220,
+    },
+    {
+      label: "淇℃墭鍩洪噾(鍏�)",
+      prop: "trustFund",
+      width: 140,
+      formatData: value =>
+        value === null || value === undefined || value === ""
+          ? "-"
+          : Number(value).toFixed(2),
+    },
+    {
+      label: "浠e偍閲戦(鍏�)",
+      prop: "depositTotalAmount",
+      dataType: "slot",
+      slot: "depositAmountSlot",
+      width: 150,
     },
     {
       label: "寮�鎴疯鍙�",
@@ -877,6 +949,8 @@
       bankAccount: "",
       bankCode: "",
       customerType: "",
+      // 閲戦瀛楁缁� null 鑰岄潪 ""锛岄伩鍏� el-input-number 鎶婄┖涓叉姌绠楁垚 0
+      trustFund: null,
       type: 0
     },
     rules: {
@@ -1576,6 +1650,11 @@
     word-break: break-word;
   }
 
+  .text-danger {
+    color: var(--el-color-danger);
+    font-weight: 600;
+  }
+
   .no-records {
     text-align: center;
     padding: 30px;
diff --git a/src/views/basicData/tankInfo/index.vue b/src/views/basicData/tankInfo/index.vue
index e748b66..a93d11e 100644
--- a/src/views/basicData/tankInfo/index.vue
+++ b/src/views/basicData/tankInfo/index.vue
@@ -18,6 +18,30 @@
                       prefix-icon="Search"
                       @change="handleQuery" />
           </el-form-item>
+          <el-form-item label="鏄惁鍚敤锛�">
+            <el-select v-model="searchForm.isEnabled"
+                       placeholder="璇烽�夋嫨"
+                       clearable
+                       style="width: 140px"
+                       @change="handleQuery">
+              <el-option label="鍚敤"
+                         :value="1" />
+              <el-option label="鏈惎鐢�"
+                         :value="0" />
+            </el-select>
+          </el-form-item>
+          <el-form-item label="鐢ㄩ�旓細">
+            <el-select v-model="searchForm.usageType"
+                       placeholder="璇烽�夋嫨"
+                       clearable
+                       style="width: 140px"
+                       @change="handleQuery">
+              <el-option label="绉熻祦"
+                         :value="1" />
+              <el-option label="鑷敤"
+                         :value="2" />
+            </el-select>
+          </el-form-item>
           <el-form-item>
             <el-button type="primary"
                        @click="handleQuery"> 鎼滅储
@@ -64,6 +88,25 @@
         <el-table-column label="搴撳瓨浣欓噺(m鲁)"
                          prop="remaining"
                          min-width="140" />
+        <el-table-column label="鏄惁鍚敤"
+                         prop="isEnabled"
+                         align="center"
+                         width="100">
+          <template #default="scope">
+            <el-tag :type="scope.row.isEnabled === 1 ? 'success' : 'info'"
+                    size="small">
+              {{ scope.row.isEnabled === 1 ? "鍚敤" : "鏈惎鐢�" }}
+            </el-tag>
+          </template>
+        </el-table-column>
+        <el-table-column label="鐢ㄩ��"
+                         prop="usageType"
+                         align="center"
+                         width="90">
+          <template #default="scope">
+            {{ getUsageTypeText(scope.row.usageType) }}
+          </template>
+        </el-table-column>
         <el-table-column label="绉熷淇℃伅"
                          prop="tenantInfo"
                          min-width="160"
@@ -172,8 +215,38 @@
             </el-form-item>
           </el-col>
           <el-col :span="12">
+            <el-form-item label="鏄惁鍚敤锛�"
+                          prop="isEnabled">
+              <el-switch v-model="form.isEnabled"
+                         :active-value="1"
+                         :inactive-value="0"
+                         active-text="鍚敤"
+                         inactive-text="鏈惎鐢�" />
+            </el-form-item>
+          </el-col>
+        </el-row>
+        <el-row :gutter="30"
+                v-if="form.isEnabled === 1">
+          <el-col :span="12">
+            <el-form-item label="鐢ㄩ�旓細"
+                          prop="usageType">
+              <el-radio-group v-model="form.usageType">
+                <el-radio :value="1">绉熻祦</el-radio>
+                <el-radio :value="2">鑷敤</el-radio>
+              </el-radio-group>
+            </el-form-item>
+          </el-col>
+          <el-col :span="12"
+                  v-if="form.usageType === 1">
             <el-form-item label="绉熷淇℃伅锛�"
-                          prop="tenantInfo">
+                          prop="tenantInfo"
+                          :rules="[
+                {
+                required: true,
+                message: '绉熻祦鐨勫偍缃愬繀椤诲~鍐欑瀹俊鎭�',
+                trigger: 'blur',
+              }
+            ]">
               <el-input v-model="form.tenantInfo"
                         placeholder="璇疯緭鍏ョ瀹俊鎭�"
                         clearable />
@@ -188,7 +261,7 @@
 <script setup>
   import FormDialog from "@/components/Dialog/FormDialog.vue";
   import pagination from "@/components/PIMTable/Pagination.vue";
-  import { ref, reactive, toRefs, getCurrentInstance } from "vue";
+  import { ref, reactive, toRefs, watch, getCurrentInstance } from "vue";
   import { Search } from "@element-plus/icons-vue";
   import { ElMessageBox } from "element-plus";
   import {
@@ -214,6 +287,8 @@
     searchForm: {
       tankNo: "",
       category: "",
+      isEnabled: "",
+      usageType: "",
     },
     form: {
       id: null,
@@ -222,6 +297,8 @@
       oilProduct: "",
       capacity: null,
       remaining: null,
+      isEnabled: 1,
+      usageType: null,
       tenantInfo: "",
     },
     rules: {
@@ -230,6 +307,24 @@
     },
   });
   const { searchForm, form, rules } = toRefs(data);
+
+  // 鐢ㄩ�旀枃妗堬細1 绉熻祦 / 2 鑷敤
+  const getUsageTypeText = value => ({ 1: "绉熻祦", 2: "鑷敤" })[value] || "--";
+
+  // 鏈惎鐢ㄦ椂鐢ㄩ�斾笌绉熷淇℃伅涓�寰嬫竻绌猴紱閫夎嚜鐢ㄦ椂绉熷淇℃伅鑷姩娓呯┖锛堢璧佹墠闇�瑕佺瀹級
+  watch(
+    () => [form.value.isEnabled, form.value.usageType],
+    () => {
+      if (form.value.isEnabled !== 1) {
+        form.value.usageType = null;
+        form.value.tenantInfo = "";
+        return;
+      }
+      if (form.value.usageType !== 1) {
+        form.value.tenantInfo = "";
+      }
+    }
+  );
 
   const getList = () => {
     tableLoading.value = true;
@@ -259,14 +354,49 @@
     selectedRows.value = selection;
   };
 
+  const buildEmptyForm = () => ({
+    id: null,
+    tankNo: "",
+    category: "",
+    oilProduct: "",
+    capacity: null,
+    remaining: null,
+    isEnabled: 1,
+    usageType: null,
+    tenantInfo: "",
+  });
+
   const openForm = (type, row) => {
     operationType.value = type;
-    form.value = {};
+    // 鍏堥噸缃啀璧嬪�硷細resetFields 浼氭妸瀛楁鎵撳洖鎸傝浇鏃剁殑鍒濆�硷紝鏀惧悗闈細鎶婂垰濉ソ鐨勫�兼竻鎺�
     proxy.resetForm("formRef");
+    form.value = buildEmptyForm();
     dialogFormVisible.value = true;
     if (type === "edit" && row) {
-      const { id, tankNo, category, oilProduct, capacity, remaining, tenantInfo } = row;
-      form.value = { id, tankNo, category, oilProduct, capacity, remaining, tenantInfo };
+      const {
+        id,
+        tankNo,
+        category,
+        oilProduct,
+        capacity,
+        remaining,
+        isEnabled,
+        usageType,
+        tenantInfo,
+      } = row;
+      form.value = {
+        ...buildEmptyForm(),
+        id,
+        tankNo,
+        category,
+        oilProduct,
+        capacity,
+        remaining,
+        // 鍘嗗彶鏁版嵁娌℃湁璇ュ瓧娈碉紝缂哄け鏃舵寜銆屽惎鐢ㄣ�嶅鐞嗭紝閬垮厤淇濆瓨鏃惰璇疆涓烘湭鍚敤
+        isEnabled: isEnabled ?? 1,
+        usageType: usageType ?? null,
+        tenantInfo: tenantInfo ?? "",
+      };
     }
   };
 
diff --git a/src/views/basicData/vehicle/index.vue b/src/views/basicData/vehicle/index.vue
new file mode 100644
index 0000000..26e2200
--- /dev/null
+++ b/src/views/basicData/vehicle/index.vue
@@ -0,0 +1,371 @@
+<template>
+  <div class="app-container">
+    <div class="search_form">
+      <div>
+        <el-form :model="searchForm"
+                 :inline="true">
+          <el-form-item label="杞︾墝鍙凤細">
+            <el-input v-model="searchForm.plateNumber"
+                      placeholder="璇疯緭鍏�"
+                      clearable
+                      prefix-icon="Search"
+                      @change="handleQuery" />
+          </el-form-item>
+          <el-form-item label="鍙告満濮撳悕锛�">
+            <el-input v-model="searchForm.driverName"
+                      placeholder="璇疯緭鍏�"
+                      clearable
+                      prefix-icon="Search"
+                      @change="handleQuery" />
+          </el-form-item>
+          <el-form-item label="鐘舵�侊細">
+            <el-select v-model="searchForm.status"
+                       placeholder="璇烽�夋嫨"
+                       clearable
+                       style="width: 160px"
+                       @change="handleQuery">
+              <el-option label="鍚敤"
+                         value="鍚敤" />
+              <el-option label="鍋滅敤"
+                         value="鍋滅敤" />
+            </el-select>
+          </el-form-item>
+          <el-form-item>
+            <el-button type="primary"
+                       @click="handleQuery"> 鎼滅储
+            </el-button>
+          </el-form-item>
+        </el-form>
+      </div>
+    </div>
+    <div class="table_list">
+      <div style="display: flex;justify-content: flex-end;margin-bottom: 20px;">
+        <el-button type="primary"
+                   @click="openForm('add')">鏂板杞﹁締</el-button>
+        <el-button type="danger"
+                   plain
+                   @click="handleDelete()">鍒犻櫎
+        </el-button>
+      </div>
+      <el-table :data="tableData"
+                border
+                v-loading="tableLoading"
+                @selection-change="handleSelectionChange">
+        <el-table-column align="center"
+                         type="selection"
+                         width="55" />
+        <el-table-column align="center"
+                         label="搴忓彿"
+                         type="index"
+                         width="60" />
+        <el-table-column label="杞︾墝鍙�"
+                         prop="plateNumber"
+                         min-width="140"
+                         show-overflow-tooltip />
+        <el-table-column label="榛樿鍙告満"
+                         prop="driverName"
+                         min-width="120"
+                         show-overflow-tooltip />
+        <el-table-column label="鍙告満鐢佃瘽"
+                         prop="driverPhone"
+                         min-width="140"
+                         show-overflow-tooltip />
+        <el-table-column label="鏍稿畾杞介噸(鍚�)"
+                         prop="loadCapacity"
+                         min-width="120" />
+        <el-table-column label="鐘舵��"
+                         prop="status"
+                         min-width="90">
+          <template #default="scope">
+            <el-tag :type="scope.row.status === '鍋滅敤' ? 'info' : 'success'"
+                    size="small">
+              {{ scope.row.status || '鍚敤' }}
+            </el-tag>
+          </template>
+        </el-table-column>
+        <el-table-column label="澶囨敞"
+                         prop="remark"
+                         min-width="160"
+                         show-overflow-tooltip />
+        <el-table-column label="鍒涘缓鏃堕棿"
+                         prop="createTime"
+                         min-width="180">
+          <template #default="scope">
+            {{ scope.row.createTime ? scope.row.createTime.replace('T', ' ').slice(0, 19) : '--' }}
+          </template>
+        </el-table-column>
+        <el-table-column fixed="right"
+                         label="鎿嶄綔"
+                         width="120"
+                         align="center">
+          <template #default="scope">
+            <el-button link
+                       type="primary"
+                       @click="openForm('edit', scope.row)">缂栬緫
+            </el-button>
+            <el-button link
+                       type="danger"
+                       @click="handleDelete([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>
+    <FormDialog v-model="dialogFormVisible"
+                :title="operationType === 'add' ? '鏂板杞﹁締' : '缂栬緫杞﹁締'"
+                :width="'40%'"
+                :operation-type="operationType"
+                @close="closeDia"
+                @confirm="submitForm"
+                @cancel="closeDia">
+      <el-form :model="form"
+               label-width="120px"
+               label-position="top"
+               :rules="rules"
+               ref="formRef">
+        <el-row :gutter="30">
+          <el-col :span="12">
+            <el-form-item label="杞︾墝鍙凤細"
+                          prop="plateNumber">
+              <el-input v-model="form.plateNumber"
+                        placeholder="璇疯緭鍏ヨ溅鐗屽彿"
+                        clearable />
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="鐘舵�侊細"
+                          prop="status">
+              <el-select v-model="form.status"
+                         placeholder="璇烽�夋嫨"
+                         style="width: 100%">
+                <el-option label="鍚敤"
+                           value="鍚敤" />
+                <el-option label="鍋滅敤"
+                           value="鍋滅敤" />
+              </el-select>
+            </el-form-item>
+          </el-col>
+        </el-row>
+        <el-row :gutter="30">
+          <el-col :span="12">
+            <el-form-item label="榛樿鍙告満锛�"
+                          prop="driverName">
+              <el-input v-model="form.driverName"
+                        placeholder="璇疯緭鍏ュ徃鏈哄鍚�"
+                        clearable />
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="鍙告満鐢佃瘽锛�"
+                          prop="driverPhone">
+              <el-input v-model="form.driverPhone"
+                        placeholder="璇疯緭鍏�11浣嶆暟瀛�"
+                        maxlength="11"
+                        @input="phoneInput"
+                        clearable />
+            </el-form-item>
+          </el-col>
+        </el-row>
+        <el-row :gutter="30">
+          <el-col :span="12">
+            <el-form-item label="鏍稿畾杞介噸(鍚�)锛�"
+                          prop="loadCapacity">
+              <el-input-number v-model="form.loadCapacity"
+                               :precision="2"
+                               :step="1"
+                               :min="0"
+                               style="width: 100%" />
+            </el-form-item>
+          </el-col>
+        </el-row>
+        <el-row :gutter="30">
+          <el-col :span="24">
+            <el-form-item label="澶囨敞锛�"
+                          prop="remark">
+              <el-input v-model="form.remark"
+                        type="textarea"
+                        :rows="2"
+                        placeholder="璇疯緭鍏ュ娉�"
+                        clearable />
+            </el-form-item>
+          </el-col>
+        </el-row>
+      </el-form>
+    </FormDialog>
+  </div>
+</template>
+
+<script setup>
+  import FormDialog from "@/components/Dialog/FormDialog.vue";
+  import pagination from "@/components/PIMTable/Pagination.vue";
+  import { ref, reactive, toRefs, getCurrentInstance } from "vue";
+  import { ElMessageBox } from "element-plus";
+  import {
+    listVehicle,
+    addVehicle,
+    updateVehicle,
+    delVehicle,
+  } from "@/api/basicData/vehicle.js";
+
+  const { proxy } = getCurrentInstance();
+  const tableData = ref([]);
+  const selectedRows = ref([]);
+  const tableLoading = ref(false);
+  const dialogFormVisible = ref(false);
+  const operationType = ref("");
+  const page = reactive({
+    current: 1,
+    size: 10,
+  });
+  const total = ref(0);
+
+  const data = reactive({
+    searchForm: {
+      plateNumber: "",
+      driverName: "",
+      status: "",
+    },
+    form: {
+      id: null,
+      plateNumber: "",
+      driverName: "",
+      driverPhone: "",
+      loadCapacity: null,
+      status: "鍚敤",
+      remark: "",
+    },
+    rules: {
+      plateNumber: [{ required: true, message: "璇疯緭鍏ヨ溅鐗屽彿", trigger: "blur" }],
+      driverPhone: [
+        { pattern: /^1[3-9]\d{9}$/, message: "璇疯緭鍏ユ湁鏁堢殑11浣嶆墜鏈哄彿鐮�", trigger: "blur" },
+      ],
+    },
+  });
+  const { searchForm, form, rules } = toRefs(data);
+
+  const getList = () => {
+    tableLoading.value = true;
+    listVehicle({ ...searchForm.value, ...page })
+      .then(res => {
+        tableLoading.value = false;
+        tableData.value = res.data.records || [];
+        total.value = res.data.total || 0;
+      })
+      .catch(() => {
+        tableLoading.value = false;
+      });
+  };
+
+  const handleQuery = () => {
+    page.current = 1;
+    getList();
+  };
+
+  const paginationChange = obj => {
+    page.current = obj.page;
+    page.size = obj.limit;
+    getList();
+  };
+
+  const handleSelectionChange = selection => {
+    selectedRows.value = selection;
+  };
+
+  // 鐢佃瘽杈撳叆闄愬埗锛氬彧鍏佽鏁板瓧锛屾渶澶�11浣�
+  const phoneInput = val => {
+    form.value.driverPhone = String(val ?? "")
+      .replace(/\D/g, "")
+      .slice(0, 11);
+  };
+
+  const openForm = (type, row) => {
+    operationType.value = type;
+    form.value = {};
+    proxy.resetForm("formRef");
+    dialogFormVisible.value = true;
+    if (type === "edit" && row) {
+      const { id, plateNumber, driverName, driverPhone, loadCapacity, status, remark } = row;
+      form.value = {
+        id,
+        plateNumber,
+        driverName,
+        driverPhone,
+        loadCapacity,
+        status: status || "鍚敤",
+        remark,
+      };
+    } else {
+      form.value = {
+        id: null,
+        plateNumber: "",
+        driverName: "",
+        driverPhone: "",
+        loadCapacity: null,
+        status: "鍚敤",
+        remark: "",
+      };
+    }
+  };
+
+  const submitForm = () => {
+    proxy.$refs["formRef"].validate(valid => {
+      if (valid) {
+        const api = form.value.id ? updateVehicle : addVehicle;
+        api(form.value).then(() => {
+          proxy.$modal.msgSuccess("鎿嶄綔鎴愬姛");
+          closeDia();
+          getList();
+        });
+      }
+    });
+  };
+
+  const closeDia = () => {
+    proxy.resetForm("formRef");
+    dialogFormVisible.value = false;
+  };
+
+  const handleDelete = rows => {
+    let ids = [];
+    if (rows) {
+      ids = rows.map(item => item.id);
+    } else if (selectedRows.value.length > 0) {
+      ids = selectedRows.value.map(item => item.id);
+    } else {
+      proxy.$modal.msgWarning("璇烽�夋嫨鏁版嵁");
+      return;
+    }
+    ElMessageBox.confirm(
+      "閫変腑鐨勫唴瀹瑰皢琚垹闄わ紝鏄惁纭鍒犻櫎锛熷缓璁敤銆屽仠鐢ㄣ�嶄笅绾胯溅杈嗭紝鍒犻櫎涓嶄細鏍¢獙鏄惁宸茶鍑哄簱璁板綍寮曠敤銆�",
+      "鍒犻櫎",
+      {
+        confirmButtonText: "纭",
+        cancelButtonText: "鍙栨秷",
+        type: "warning",
+      }
+    )
+      .then(() => {
+        delVehicle(ids).then(() => {
+          proxy.$modal.msgSuccess("鍒犻櫎鎴愬姛");
+          getList();
+        });
+      })
+      .catch(() => {
+        proxy.$modal.msg("宸插彇娑�");
+      });
+  };
+
+  getList();
+</script>
+
+<style scoped lang="scss">
+  .search_form {
+    margin-bottom: 16px;
+  }
+</style>
diff --git a/src/views/equipmentManagement/spareParts/index.vue b/src/views/equipmentManagement/spareParts/index.vue
index 9f5d8fe..dccc99b 100644
--- a/src/views/equipmentManagement/spareParts/index.vue
+++ b/src/views/equipmentManagement/spareParts/index.vue
@@ -63,6 +63,35 @@
             <el-form-item label="澶囦欢缂栧彿" prop="sparePartsNo">
               <el-input v-model="form.sparePartsNo"></el-input>
             </el-form-item>
+            <el-form-item label="浜у搧澶х被" prop="productId">
+              <el-tree-select
+                v-model="form.productId"
+                placeholder="璇烽�夋嫨"
+                clearable
+                filterable
+                check-strictly
+                :data="productOptions"
+                :render-after-expand="false"
+                @change="handleProductChange"
+                style="width: 100%"
+              />
+            </el-form-item>
+            <el-form-item label="瑙勬牸鍨嬪彿" prop="productModelId">
+              <el-select
+                v-model="form.productModelId"
+                placeholder="璇烽�夋嫨"
+                clearable
+                filterable
+                style="width: 100%"
+              >
+                <el-option
+                  v-for="item in modelOptions"
+                  :key="item.id"
+                  :label="item.model"
+                  :value="item.id"
+                />
+              </el-select>
+            </el-form-item>
             <el-form-item label="鏁伴噺" prop="quantity">
               <el-input type="number" v-model="form.quantity"></el-input>
             </el-form-item>
@@ -134,6 +163,7 @@
 import { ElMessage, ElMessageBox } from 'element-plus';
 import { getSparePartsList, addSparePart, editSparePart, delSparePart } from "@/api/equipmentManagement/spareParts";
 import { getDeviceLedger } from "@/api/equipmentManagement/ledger";
+import { productTreeList, modelList } from "@/api/basicData/product.js";
 import PIMTable from "@/components/PIMTable/PIMTable.vue";
 import { getSparePartsUsagePage } from "@/api/equipmentManagement/sparePartsUsage";
 
@@ -153,6 +183,9 @@
 const operationType = ref('add')
 // 璁惧閫夐」
 const deviceOptions = ref([]);
+// 浜у搧澶х被鏍�/瑙勬牸鍨嬪彿閫夐」
+const productOptions = ref([]);
+const modelOptions = ref([]);
 // 琛ㄥ崟寮曠敤
 const formRef = ref(null);
 // 鏌ヨ鍙傛暟
@@ -253,6 +286,8 @@
   id:'',
   name: '',
   sparePartsNo: '',
+  productId: '',
+  productModelId: '',
   status: '',
   description: '',
   deviceLedgerIds: [],
@@ -415,17 +450,55 @@
   }
 };
 
+// 鍔犺浇浜у搧澶х被鏍戯紙id -> value锛屼緵 el-tree-select 浣跨敤锛�
+const loadProductOptions = async () => {
+  try {
+    const res = await productTreeList();
+    productOptions.value = convertIdToValue(Array.isArray(res) ? res : res?.data || []);
+  } catch (error) {
+    ElMessage.error('鑾峰彇浜у搧澶х被澶辫触');
+  }
+};
+
+function convertIdToValue(data) {
+  return (data || []).map(item => {
+    const { id, children, ...rest } = item;
+    const newItem = { ...rest, value: id };
+    if (children && children.length > 0) {
+      newItem.children = convertIdToValue(children);
+    }
+    return newItem;
+  });
+}
+
+// 鍒囨崲浜у搧澶х被锛氭竻绌鸿鏍煎瀷鍙峰苟閲嶆柊鎷夊彇瑙勬牸鍨嬪彿閫夐」
+const handleProductChange = async value => {
+  form.productModelId = '';
+  modelOptions.value = [];
+  if (!value) return;
+  try {
+    const res = await modelList({ id: value });
+    modelOptions.value = Array.isArray(res) ? res : res?.data || [];
+  } catch (error) {
+    ElMessage.error('鑾峰彇瑙勬牸鍨嬪彿澶辫触');
+  }
+};
+
 // 鏂板鍒嗙被
 const addCategory = async () => {
   await loadDeviceName();
+  await loadProductOptions();
   form.id = '';
   form.name = '';
   form.sparePartsNo = '';
+  form.productId = '';
+  form.productModelId = '';
   form.status = '';
   form.description = '';
   form.deviceLedgerIds = [];
   form.quantity = undefined;
   form.price = null;
+  modelOptions.value = [];
   operationType.value = 'add'
   dialogVisible.value = true;
 };
@@ -433,7 +506,21 @@
 // 缂栬緫鍒嗙被
 const editCategory = async (row) => {
   await loadDeviceName();
+  await loadProductOptions();
   Object.assign(form, row);
+  form.productId = row.productId ?? '';
+  form.productModelId = row.productModelId ?? '';
+  // 鍙嶆樉瑙勬牸鍨嬪彿閫夐」锛堢紪杈戞椂涓嶄細瑙﹀彂浜у搧澶х被 change锛�
+  if (form.productId) {
+    try {
+      const res = await modelList({ id: form.productId });
+      modelOptions.value = Array.isArray(res) ? res : res?.data || [];
+    } catch (error) {
+      modelOptions.value = [];
+    }
+  } else {
+    modelOptions.value = [];
+  }
   // 濡傛灉鍚庣杩斿洖鐨勬槸 deviceIds 瀛楃涓诧紝闇�瑕佽浆鎹负鏁扮粍
   if (row.deviceIds && typeof row.deviceIds === 'string') {
     // 纭繚ID绫诲瀷涓庤澶囬�夐」涓殑ID绫诲瀷涓�鑷�
diff --git a/src/views/equipmentManagement/sparePartsRecord/index.vue b/src/views/equipmentManagement/sparePartsRecord/index.vue
new file mode 100644
index 0000000..2fb306e
--- /dev/null
+++ b/src/views/equipmentManagement/sparePartsRecord/index.vue
@@ -0,0 +1,215 @@
+<template>
+  <div class="app-container">
+    <div class="search_form">
+      <el-form :inline="true" :model="searchForm">
+        <el-form-item label="澶囦欢">
+          <el-select v-model="searchForm.sparePartsId"
+                     placeholder="璇烽�夋嫨"
+                     clearable
+                     filterable
+                     style="width: 240px">
+            <el-option v-for="item in sparePartsOptions"
+                       :key="item.id"
+                       :label="item.name"
+                       :value="item.id" />
+          </el-select>
+        </el-form-item>
+        <el-form-item label="鏂瑰悜">
+          <el-select v-model="searchForm.direction"
+                     placeholder="璇烽�夋嫨"
+                     clearable
+                     style="width: 160px">
+            <el-option label="鍏ュ簱" :value="1" />
+            <el-option label="鍑哄簱" :value="2" />
+          </el-select>
+        </el-form-item>
+        <el-form-item label="鏉ユ簮绫诲瀷">
+          <el-select v-model="searchForm.sourceType"
+                     placeholder="璇烽�夋嫨"
+                     clearable
+                     style="width: 160px">
+            <el-option v-for="item in sourceTypeOptions"
+                       :key="item.value"
+                       :label="item.label"
+                       :value="item.value" />
+          </el-select>
+        </el-form-item>
+        <el-form-item>
+          <el-button type="primary" @click="handleQuery">鏌ヨ</el-button>
+          <el-button @click="resetQuery">閲嶇疆</el-button>
+        </el-form-item>
+      </el-form>
+      <div>
+        <el-button type="danger" plain @click="handleDelete">鍒犻櫎</el-button>
+      </div>
+    </div>
+    <div class="table_list">
+      <el-table :data="tableData"
+                border
+                v-loading="tableLoading"
+                @selection-change="handleSelectionChange"
+                :row-key="row => row.id"
+                height="calc(100vh - 18.5em)">
+        <el-table-column align="center" type="selection" width="55" />
+        <el-table-column align="center" label="搴忓彿" type="index" width="60" />
+        <el-table-column label="澶囦欢鍚嶇О" prop="sparePartsName" show-overflow-tooltip />
+        <el-table-column label="鏂瑰悜" width="100">
+          <template #default="{ row }">
+            <el-tag :type="row.direction === 1 || row.direction === '1' ? 'success' : 'warning'"
+                    size="small">
+              {{ getDirectionText(row.direction) }}
+            </el-tag>
+          </template>
+        </el-table-column>
+        <el-table-column label="鏁伴噺" prop="quantity" width="120" show-overflow-tooltip />
+        <el-table-column label="鏉ユ簮绫诲瀷" prop="sourceType" width="120" show-overflow-tooltip>
+          <template #default="{ row }">
+            {{ getSourceTypeText(row.sourceType) }}
+          </template>
+        </el-table-column>
+        <el-table-column label="鏉ユ簮鍗曞彿" prop="sourceNo" show-overflow-tooltip />
+        <el-table-column label="澶囨敞" prop="remark" show-overflow-tooltip />
+        <el-table-column label="鏃堕棿" prop="createTime" width="170" show-overflow-tooltip />
+      </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>
+  </div>
+</template>
+
+<script setup>
+  import pagination from "@/components/PIMTable/Pagination.vue";
+  import { ref, reactive, getCurrentInstance } from "vue";
+  import { ElMessageBox } from "element-plus";
+  import {
+    getSparePartsRecordPage,
+    delSparePartsRecord,
+  } from "@/api/equipmentManagement/sparePartsRecord.js";
+  import { getSparePartsList } from "@/api/equipmentManagement/spareParts.js";
+
+  const { proxy } = getCurrentInstance();
+
+  const tableData = ref([]);
+  const selectedRows = ref([]);
+  const tableLoading = ref(false);
+  const total = ref(0);
+  const page = reactive({
+    current: 1,
+    size: 10,
+  });
+  const searchForm = ref({
+    sparePartsId: "",
+    direction: "",
+    sourceType: "",
+  });
+  // 澶囦欢涓嬫媺閫夐」
+  const sparePartsOptions = ref([]);
+  // 鏉ユ簮绫诲瀷鏋氫妇
+  const sourceTypeOptions = [
+    { label: "閲囪喘鍏ュ簱", value: 1 },
+    { label: "缁翠慨棰嗙敤", value: 2 },
+    { label: "淇濆吇棰嗙敤", value: 3 },
+  ];
+
+  const getDirectionText = direction => {
+    const map = { 1: "鍏ュ簱", 2: "鍑哄簱" };
+    return map[direction] || "";
+  };
+
+  const getSourceTypeText = sourceType => {
+    return (
+      sourceTypeOptions.find(item => item.value === sourceType)?.label || ""
+    );
+  };
+
+  const getList = () => {
+    tableLoading.value = true;
+    getSparePartsRecordPage({
+      ...searchForm.value,
+      current: page.current,
+      size: page.size,
+    })
+      .then(res => {
+        tableLoading.value = false;
+        const result = res.data || {};
+        tableData.value = result.records || [];
+        total.value = result.total || 0;
+      })
+      .catch(() => {
+        tableLoading.value = false;
+      });
+  };
+
+  const loadSparePartsOptions = () => {
+    getSparePartsList({ current: 1, size: 1000 })
+      .then(res => {
+        sparePartsOptions.value = res?.data?.records || [];
+      })
+      .catch(() => {
+        sparePartsOptions.value = [];
+      });
+  };
+
+  const handleQuery = () => {
+    page.current = 1;
+    getList();
+  };
+
+  const resetQuery = () => {
+    searchForm.value = {
+      sparePartsId: "",
+      direction: "",
+      sourceType: "",
+    };
+    page.current = 1;
+    getList();
+  };
+
+  const paginationChange = obj => {
+    page.current = obj.page;
+    page.size = obj.limit;
+    getList();
+  };
+
+  const handleSelectionChange = selection => {
+    selectedRows.value = selection.filter(item => item.id);
+  };
+
+  const handleDelete = () => {
+    if (selectedRows.value.length === 0) {
+      proxy.$modal.msgWarning("璇烽�夋嫨鏁版嵁");
+      return;
+    }
+    const ids = selectedRows.value.map(item => item.id);
+    ElMessageBox.confirm("閫変腑鐨勫唴瀹瑰皢琚垹闄わ紝鏄惁纭鍒犻櫎锛�", "鍒犻櫎", {
+      confirmButtonText: "纭",
+      cancelButtonText: "鍙栨秷",
+      type: "warning",
+    })
+      .then(() => {
+        delSparePartsRecord(ids).then(() => {
+          proxy.$modal.msgSuccess("鍒犻櫎鎴愬姛");
+          getList();
+        });
+      })
+      .catch(() => {
+        proxy.$modal.msg("宸插彇娑�");
+      });
+  };
+
+  getList();
+  loadSparePartsOptions();
+</script>
+
+<style scoped lang="scss">
+  .search_form {
+    display: flex;
+    align-items: flex-start;
+    justify-content: space-between;
+    margin-bottom: 10px;
+  }
+</style>
diff --git a/src/views/inventoryManagement/dispatchLog/Record.vue b/src/views/inventoryManagement/dispatchLog/Record.vue
index 5a056d6..5658104 100644
--- a/src/views/inventoryManagement/dispatchLog/Record.vue
+++ b/src/views/inventoryManagement/dispatchLog/Record.vue
@@ -18,7 +18,7 @@
             </el-form-item>
           </el-col>
           <el-col :span="4">
-            <el-form-item label="浜у搧澶х被"
+            <el-form-item label="娌瑰搧"
                           prop="productName">
               <el-input v-model="searchForm.productName"
                         style="width: 240px"
@@ -102,46 +102,211 @@
                          label="搴忓彿"
                          type="index"
                          width="60" />
-        <el-table-column label="鍑哄簱鎵规"
-                         prop="outboundBatches"
-                         min-width="100"
-                         show-overflow-tooltip />
-        <el-table-column label="鍑哄簱鏃ユ湡"
-                         prop="createTime"
-                         show-overflow-tooltip />
-        <el-table-column label="浜у搧澶х被"
-                         prop="productName"
-                         show-overflow-tooltip />
-        <el-table-column label="瑙勬牸鍨嬪彿"
-                         prop="model"
-                         show-overflow-tooltip />
-        <el-table-column label="鎵瑰彿"
-                         prop="batchNo"
-                         show-overflow-tooltip />
-        <el-table-column label="鍗曚綅"
-                         prop="unit"
-                         show-overflow-tooltip />
-        <el-table-column label="鍑哄簱鏁伴噺"
-                         prop="stockOutNum"
-                         show-overflow-tooltip />
-        <el-table-column label="鍑哄簱浜�"
-                         prop="createBy"
-                         show-overflow-tooltip />
-        <el-table-column label="鏉ユ簮"
-                         prop="recordType"
-                         show-overflow-tooltip>
-          <template #default="scope">
-            {{ getRecordType(scope.row.recordType) }}
-          </template>
+        <el-table-column label="鍑哄簱淇℃伅"
+                         align="center"
+                         :header-cell-style="groupHeaderStyle">
+          <el-table-column label="鍑哄簱鎵规"
+                           prop="outboundBatches"
+                           min-width="120"
+                           show-overflow-tooltip />
+          <el-table-column label="鍑哄簱鏃ユ湡"
+                           prop="outDate"
+                           min-width="110"
+                           show-overflow-tooltip />
+          <el-table-column label="鍑哄簱绫诲埆"
+                           prop="outCategory"
+                           min-width="90"
+                           show-overflow-tooltip />
+          <el-table-column label="娌瑰簱"
+                           prop="oilDepotName"
+                           min-width="160"
+                           show-overflow-tooltip />
+          <el-table-column label="鍌ㄧ綈鍙�"
+                           prop="tankNo"
+                           min-width="90"
+                           show-overflow-tooltip />
+          <el-table-column label="娌瑰搧"
+                           prop="productName"
+                           min-width="90"
+                           show-overflow-tooltip />
+          <el-table-column label="鍑哄簱鍚ㄦ暟(鍚�)"
+                           prop="outTonnage"
+                           min-width="110"
+                           show-overflow-tooltip />
+          <el-table-column label="瑙勬牸鍨嬪彿"
+                           prop="model"
+                           min-width="110"
+                           show-overflow-tooltip />
+          <el-table-column label="鎵瑰彿"
+                           prop="batchNo"
+                           min-width="140"
+                           show-overflow-tooltip />
+          <el-table-column label="鍗曚綅"
+                           prop="unit"
+                           min-width="70"
+                           show-overflow-tooltip />
+          <el-table-column label="鍑哄簱鏁伴噺"
+                           prop="stockOutNum"
+                           min-width="100"
+                           show-overflow-tooltip />
+          <el-table-column label="瀹為檯鎵e噺鏁伴噺"
+                           prop="deductQuantity"
+                           min-width="120"
+                           show-overflow-tooltip />
+          <el-table-column label="鍓╀綑娌归噺(鍚�)"
+                           prop="residualOil"
+                           min-width="110"
+                           show-overflow-tooltip />
+          <el-table-column label="鍑哄簱浜�"
+                           prop="createBy"
+                           min-width="90"
+                           show-overflow-tooltip />
+          <el-table-column label="鍙戣揣鍗曞彿"
+                           prop="shippingNo"
+                           min-width="140"
+                           show-overflow-tooltip />
+          <el-table-column label="鏉ユ簮"
+                           prop="recordType"
+                           min-width="90"
+                           show-overflow-tooltip>
+            <template #default="scope">
+              {{ getRecordType(scope.row.recordType) }}
+            </template>
+          </el-table-column>
+          <el-table-column label="瀹℃壒鐘舵��"
+                           prop="approvalStatus"
+                           min-width="100"
+                           show-overflow-tooltip>
+            <template #default="scope">
+              <el-tag :type="getApprovalStatusTagType(scope.row.approvalStatus)"
+                      size="small">
+                {{ getApprovalStatusLabel(scope.row.approvalStatus) }}
+              </el-tag>
+            </template>
+          </el-table-column>
         </el-table-column>
-        <el-table-column label="瀹℃壒鐘舵��"
-                         prop="approvalStatus"
-                         show-overflow-tooltip>
+        <el-table-column label="瀹㈡埛淇℃伅"
+                         align="center"
+                         :header-cell-style="groupHeaderStyle">
+          <el-table-column label="瀹㈡埛鍚嶇О"
+                           prop="customerName"
+                           min-width="160"
+                           show-overflow-tooltip />
+          <el-table-column label="瀹㈡埛瀵规帴浜�"
+                           prop="contactPerson"
+                           min-width="100"
+                           show-overflow-tooltip />
+          <el-table-column label="瀵规帴浜虹數璇�"
+                           prop="contactPhone"
+                           min-width="120"
+                           show-overflow-tooltip />
+        </el-table-column>
+        <el-table-column label="鐗╂祦淇℃伅"
+                         align="center"
+                         :header-cell-style="groupHeaderStyle">
+          <el-table-column label="鍙告満濮撳悕"
+                           prop="driverName"
+                           min-width="100"
+                           show-overflow-tooltip />
+          <el-table-column label="鍙告満鐢佃瘽"
+                           prop="driverPhone"
+                           min-width="120"
+                           show-overflow-tooltip />
+          <el-table-column label="鎶艰繍鍛樺鍚�"
+                           prop="escortName"
+                           min-width="100"
+                           show-overflow-tooltip />
+          <el-table-column label="鎶艰繍鍛樼數璇�"
+                           prop="escortPhone"
+                           min-width="120"
+                           show-overflow-tooltip />
+          <el-table-column label="杞︾墝鍙�"
+                           prop="truckPlateNo"
+                           min-width="110"
+                           show-overflow-tooltip />
+          <el-table-column label="杞︽寕鐗屽彿"
+                           prop="trailerPlateNo"
+                           min-width="110"
+                           show-overflow-tooltip />
+        </el-table-column>
+        <el-table-column label="瑁呮补鎿嶄綔淇℃伅"
+                         align="center"
+                         :header-cell-style="groupHeaderStyle">
+          <el-table-column label="瑁呮补妫�楠�"
+                           prop="loadingInspectionStatus"
+                           min-width="90"
+                           show-overflow-tooltip />
+          <el-table-column label="瑁呰溅楣や綅"
+                           prop="loadingCranePosition"
+                           min-width="100"
+                           show-overflow-tooltip />
+          <el-table-column label="瀵嗗害"
+                           prop="density"
+                           min-width="80"
+                           show-overflow-tooltip />
+          <el-table-column label="瑁呮补鎷嶇収"
+                           prop="loadingPhotos"
+                           align="center"
+                           min-width="90">
+            <template #default="scope">
+              <el-image v-if="toPhotoArray(scope.row.loadingPhotos).length"
+                        :src="getPhotoUrl(toPhotoArray(scope.row.loadingPhotos)[0])"
+                        :preview-src-list="getPhotoUrls(scope.row.loadingPhotos)"
+                        preview-teleported
+                        fit="cover"
+                        style="width: 40px; height: 40px; border-radius: 4px" />
+              <span v-else>--</span>
+            </template>
+          </el-table-column>
+        </el-table-column>
+        <el-table-column label="鍑哄簱杩囩鏁版嵁"
+                         align="center"
+                         :header-cell-style="groupHeaderStyle">
+          <el-table-column label="姣涢噸(鍚�)"
+                           prop="grossWeight"
+                           min-width="90"
+                           show-overflow-tooltip />
+          <el-table-column label="鐨噸(鍚�)"
+                           prop="tareWeight"
+                           min-width="90"
+                           show-overflow-tooltip />
+          <el-table-column label="鍑�閲�(鍚�)"
+                           prop="netWeight"
+                           min-width="90"
+                           show-overflow-tooltip />
+          <el-table-column label="浜忛噺(鍚�)"
+                           prop="lossQuantity"
+                           min-width="90"
+                           show-overflow-tooltip />
+          <el-table-column label="瀹為檯鍑哄簱浣撶Н(鍗�)"
+                           prop="actualVolume"
+                           min-width="130"
+                           show-overflow-tooltip />
+          <el-table-column label="纾呭崟"
+                           prop="poundPhotos"
+                           align="center"
+                           min-width="90">
+            <template #default="scope">
+              <el-image v-if="toPhotoArray(scope.row.poundPhotos).length"
+                        :src="getPhotoUrl(toPhotoArray(scope.row.poundPhotos)[0])"
+                        :preview-src-list="getPhotoUrls(scope.row.poundPhotos)"
+                        preview-teleported
+                        fit="cover"
+                        style="width: 40px; height: 40px; border-radius: 4px" />
+              <span v-else>--</span>
+            </template>
+          </el-table-column>
+        </el-table-column>
+        <el-table-column fixed="right"
+                         label="鎿嶄綔"
+                         width="110"
+                         align="center">
           <template #default="scope">
-            <el-tag :type="getApprovalStatusTagType(scope.row.approvalStatus)"
-                    size="small">
-              {{ getApprovalStatusLabel(scope.row.approvalStatus) }}
-            </el-tag>
+            <el-button v-if="isSalesOutRecord(scope.row)"
+                       link
+                       type="primary"
+                       @click="openResidualOil(scope.row)">褰曞叆娈嬫补
+            </el-button>
           </template>
         </el-table-column>
       </el-table>
@@ -152,6 +317,41 @@
                   :limit="page.size"
                   @pagination="paginationChange" />
     </div>
+    <!-- 娈嬫补褰曞叆锛氶�佸畬璐у悗鍥炲~鍓╀綑娌归噺锛屽彧鏇存柊 residualOil 涓�鍒� -->
+    <el-dialog v-model="residualDialogVisible"
+               title="褰曞叆鍓╀綑娌归噺"
+               width="30%"
+               append-to-body>
+      <el-form label-width="130px"
+               label-position="top">
+        <el-form-item label="鍑哄簱鎵规">
+          <el-input :model-value="residualForm.outboundBatches || '--'"
+                    readonly />
+        </el-form-item>
+        <el-form-item label="杞︾墝鍙�">
+          <el-input :model-value="residualForm.truckPlateNo || '--'"
+                    readonly />
+        </el-form-item>
+        <el-form-item label="鍑哄簱鏁伴噺(鍚�)">
+          <el-input :model-value="residualForm.stockOutNum ?? '--'"
+                    readonly />
+        </el-form-item>
+        <el-form-item label="鍓╀綑娌归噺(鍚�)">
+          <el-input-number v-model="residualForm.residualOil"
+                           :precision="4"
+                           :step="1"
+                           :min="0"
+                           style="width: 100%" />
+        </el-form-item>
+      </el-form>
+      <template #footer>
+        <div class="dialog-footer">
+          <el-button type="primary"
+                     @click="submitResidualOil">纭</el-button>
+          <el-button @click="residualDialogVisible = false">鍙栨秷</el-button>
+        </div>
+      </template>
+    </el-dialog>
   </div>
 </template>
 
@@ -166,6 +366,7 @@
     delPendingStockOut,
     batchApproveStockOutRecords,
     batchUnapproveStockOutRecords,
+    updateResidualOil,
   } from "@/api/inventoryManagement/stockOut.js";
   import {
     findAllQualifiedStockOutRecordTypeOptions,
@@ -290,6 +491,40 @@
     return "warning";
   };
 
+  // 鍒嗙粍鐖惰〃澶存牱寮忥細鍖哄垎鍚勫垎绫�
+  const groupHeaderStyle = {
+    background: "#e8f3ff",
+    color: "#1d6fd8",
+    fontWeight: "700",
+    fontSize: "13px",
+  };
+
+  // 鐓х墖瀛楁鍚庣瀛樼殑鏄� JSON 瀛楃涓诧紝鍑哄弬闇�鑷瑙f瀽
+  const toPhotoArray = value => {
+    if (!value) {
+      return [];
+    }
+    if (Array.isArray(value)) {
+      return value;
+    }
+    if (typeof value === "string") {
+      try {
+        const parsed = JSON.parse(value);
+        return Array.isArray(parsed) ? parsed : [];
+      } catch (e) {
+        return [];
+      }
+    }
+    return [];
+  };
+
+  const getPhotoUrl = photo =>
+    typeof photo === "string" ? photo : photo?.url || photo?.previewURL || "";
+
+  // 鍥剧墖鍒楋細鍙栧叏閮ㄥ湴鍧�鐢ㄤ簬棰勮
+  const getPhotoUrls = photos =>
+    toPhotoArray(photos).map(getPhotoUrl).filter(Boolean);
+
   // 鑾峰彇鏉ユ簮绫诲瀷閫夐」
   const fetchStockRecordTypeOptions = () => {
     if (props.type === "0") {
@@ -349,6 +584,54 @@
 
   const expandedRowKeys = ref([]);
 
+  // 娈嬫补褰曞叆锛氬彧瀵归攢鍞被鍑哄簱寮�鏀撅紙娈嬫补閾惧彧瀵� outCategory='閿�鍞�' 鐢熸晥锛�
+  const residualDialogVisible = ref(false);
+  const residualForm = ref({
+    id: null,
+    outboundBatches: "",
+    truckPlateNo: "",
+    stockOutNum: null,
+    residualOil: null,
+  });
+
+  const isSalesOutRecord = row => row?.outCategory === "閿�鍞�";
+
+  const openResidualOil = row => {
+    residualForm.value = {
+      id: row.id,
+      outboundBatches: row.outboundBatches || "",
+      truckPlateNo: row.truckPlateNo || "",
+      stockOutNum: row.stockOutNum ?? null,
+      residualOil: row.residualOil ?? null,
+    };
+    residualDialogVisible.value = true;
+  };
+
+  const submitResidualOil = () => {
+    const { id, residualOil, stockOutNum } = residualForm.value;
+    if (residualOil === null || residualOil === undefined || residualOil === "") {
+      proxy.$modal.msgWarning("璇疯緭鍏ュ墿浣欐补閲�");
+      return;
+    }
+    if (Number(residualOil) < 0) {
+      proxy.$modal.msgWarning("鍓╀綑娌归噺涓嶈兘灏忎簬0");
+      return;
+    }
+    if (
+      stockOutNum !== null &&
+      stockOutNum !== undefined &&
+      Number(residualOil) > Number(stockOutNum)
+    ) {
+      proxy.$modal.msgWarning("鍓╀綑娌归噺涓嶈兘澶т簬鍑哄簱鏁伴噺");
+      return;
+    }
+    updateResidualOil(id, { residualOil }).then(() => {
+      proxy.$modal.msgSuccess("褰曞叆鎴愬姛");
+      residualDialogVisible.value = false;
+      getList();
+    });
+  };
+
   const handleBatchApprove = () => {
     if (selectedRows.value.length === 0) {
       proxy.$modal.msgWarning("璇烽�夋嫨鏁版嵁");
diff --git a/src/views/inventoryManagement/issueManagement/index.vue b/src/views/inventoryManagement/issueManagement/index.vue
index 2bba7d0..f89648f 100644
--- a/src/views/inventoryManagement/issueManagement/index.vue
+++ b/src/views/inventoryManagement/issueManagement/index.vue
@@ -53,8 +53,15 @@
     </div>
     <el-dialog v-model="dialogFormVisible" :title="'鏂板鍑哄簱'" width="40%" @close="closeDia">
       <el-form :model="form" label-width="140px" label-position="top" :rules="rules" ref="formRef">
-        <el-form-item label="鍑哄簱鏁伴噺锛�" prop="salesContractNo">
+        <el-form-item label="鍑哄簱鏁伴噺锛�" prop="inboundQuantity">
           <el-input-number :step="0.01" :min="0" style="width: 100%" v-model="form.inboundQuantity" placeholder="璇疯緭鍏�" clearable />
+        </el-form-item>
+        <el-form-item label="鍑哄簱鎵规锛�" prop="batchNo">
+          <el-select v-model="form.batchNo" placeholder="璇烽�夋嫨鍑哄簱鎵规" clearable filterable
+            v-loading="batchLoading" style="width: 100%">
+            <el-option v-for="item in batchOptions" :key="item.batchNo"
+              :label="`${item.batchNo}锛堝彲鐢� ${item.availableQuantity}锛塦" :value="item.batchNo" />
+          </el-select>
         </el-form-item>
         <el-form-item label="鍑哄簱鏃ユ湡锛�" prop="projectName">
           <el-date-picker style="width: 100%" v-model="form.inboundTime" value-format="YYYY-MM-DD" format="YYYY-MM-DD"
@@ -89,6 +96,7 @@
   getStockManagePage,
     delStockManage,
     stockOut,
+    getBatchNoList,
 } from "@/api/inventoryManagement/stockManage.js";
 
 const userStore = useUserStore()
@@ -121,6 +129,7 @@
   rules: {
     inboundTime: [{ required: true, message: "璇烽�夋嫨", trigger: "change" }],
     inboundQuantity: [{ required: true, message: "璇疯緭鍏�", trigger: "blur" }],
+    batchNo: [{ required: true, message: "璇烽�夋嫨鍑哄簱鎵规", trigger: "change" }],
     nickname: [{ required: true, message: "璇烽�夋嫨", trigger: "change" }]
   }
 })
@@ -179,6 +188,10 @@
 
 const currentRowNum = ref(0)
 const salesLedgerProductId = ref(null);
+const currentRowProductModelId = ref(null)
+// 鍑哄簱鎵规鍙�夐」锛堝彲鐢ㄩ噺 = 搴撳瓨閲� - 閿佸畾鏁伴噺锛�
+const batchOptions = ref([])
+const batchLoading = ref(false)
 
 // 鎵撳紑寮规
 const openForm = async (row) => {
@@ -186,15 +199,18 @@
   currentRowId.value = row.id
   currentRowNum.value = row.inboundNum0
   salesLedgerProductId.value = row.salesLedgerProductId
+  currentRowProductModelId.value = row.productModelId
   form.value = {}
   // 鍒濆鍖栬〃鍗曟暟鎹�
   form.value = {
     productrecordId: '',
     inboundQuantity: '', // 鍑哄簱鏁伴噺娓呯┖
+    batchNo: '', // 鍑哄簱鎵规娓呯┖
     inboundTime: getCurrentDate(), // 榛樿褰撳墠鏃ユ湡
     nickName: '', // 榛樿褰撳墠鐢ㄦ埛
   }
   console.log('form',form.value)
+  loadBatchOptions()
   // 鍔犺浇鐢ㄦ埛鍒楄〃
   try {
     const userLists = await userListNoPageByTenantId()
@@ -204,17 +220,47 @@
   }
 }
 
+// 鍔犺浇瑙勬牸鍨嬪彿涓嬬殑鍙敤鎵规
+const loadBatchOptions = async () => {
+  batchOptions.value = []
+  if (!currentRowProductModelId.value) {
+    proxy.$modal.msgWarning('褰撳墠璁板綍缂哄皯瑙勬牸鍨嬪彿锛屾棤娉曟煡璇㈠嚭搴撴壒娆�')
+    return
+  }
+  batchLoading.value = true
+  try {
+    const res = await getBatchNoList(currentRowProductModelId.value)
+    batchOptions.value = res.data || []
+  } catch (error) {
+    console.error('鏌ヨ鍑哄簱鎵规澶辫触:', error)
+  } finally {
+    batchLoading.value = false
+  }
+}
+
 // 鎻愪氦琛ㄥ崟
 const submitForm = () => {
   let num = Number(form.value.inboundQuantity)
   if(num <= 0 || num > currentRowNum.value){
     return proxy.$modal.msgWarning("璇峰~鍏ユ湁鏁堟暟瀛�")
   }
+  // 搴撳瓨鎸夋壒娆$鐞嗐�佹棤鍏堣繘鍏堝嚭锛屾暟閲忎笉鑳借秴杩囨墍閫夋壒娆$殑鍙敤閲�
+  const selectedBatch = batchOptions.value.find(
+    item => item.batchNo === form.value.batchNo
+  )
+  if (selectedBatch && num > Number(selectedBatch.availableQuantity)) {
+    return proxy.$modal.msgWarning(
+      `鍑哄簱鏁伴噺涓嶈兘瓒呰繃鎵规銆�${selectedBatch.batchNo}銆嶇殑鍙敤閲� ${selectedBatch.availableQuantity}`
+    )
+  }
   proxy.$refs["formRef"].validate(valid => {
     if (valid && currentRowId.value) {
       const outData = {
         id: currentRowId.value, // 鍘熷璁板綍ID
+        type: 2, // 2=閿�鍞嚭搴擄紝鍑哄簱鍗宠嚜鍔ㄧ敓鎴愬彂璐у彴璐�
         salesLedgerProductId: salesLedgerProductId.value,
+        productModelId: currentRowProductModelId.value,
+        batchNo: form.value.batchNo, // 鍑哄簱鎵规锛堥攢鍞嚭搴撳繀濉級
         quantity: form.value.inboundQuantity, // 鍑哄簱鏁伴噺
         time: form.value.inboundTime, // 鍑哄簱鏃堕棿
         userId: form.value.nickName // 鎿嶄綔浜�
diff --git a/src/views/inventoryManagement/receiptManagement/Record.vue b/src/views/inventoryManagement/receiptManagement/Record.vue
index 0a01def..d52ffaf 100644
--- a/src/views/inventoryManagement/receiptManagement/Record.vue
+++ b/src/views/inventoryManagement/receiptManagement/Record.vue
@@ -18,7 +18,7 @@
             </el-form-item>
           </el-col>
           <el-col :span="4">
-            <el-form-item label="浜у搧澶х被"
+            <el-form-item label="娌瑰搧"
                           prop="productName">
               <el-input v-model="searchForm.productName"
                         style="width: 240px"
@@ -103,56 +103,197 @@
                          label="搴忓彿"
                          type="index"
                          width="60" />
-        <el-table-column label="鍏ュ簱鎵规"
-                         prop="inboundBatches"
-                         width="200"
-                         show-overflow-tooltip />
-        <el-table-column label="鍏ュ簱鏃堕棿"
-                         prop="createTime"
-                         show-overflow-tooltip />
-        <el-table-column label="浜у搧澶х被"
-                         prop="productName"
-                         show-overflow-tooltip />
-        <el-table-column label="瑙勬牸鍨嬪彿"
-                         prop="model"
-                         show-overflow-tooltip />
-        <el-table-column label="鎵瑰彿"
-                         prop="batchNo"
-                         show-overflow-tooltip />
-        <el-table-column label="鍗曚綅"
-                         prop="unit"
-                         show-overflow-tooltip />
-        <el-table-column label="鍏ュ簱鏁伴噺"
-                         prop="stockInNum"
-                         show-overflow-tooltip />
-        <el-table-column label="鍏ュ簱浜�"
-                         prop="createBy"
-                         show-overflow-tooltip />
-        <el-table-column label="鏉ユ簮"
-                         prop="recordType"
-                         show-overflow-tooltip>
-          <template #default="scope">
-            {{ getRecordType(scope.row.recordType) }}
-          </template>
+        <el-table-column label="鍏ュ簱淇℃伅"
+                         align="center"
+                         :header-cell-style="groupHeaderStyle">
+          <el-table-column label="鍏ュ簱鎵规"
+                           prop="inboundBatches"
+                           min-width="150"
+                           show-overflow-tooltip />
+          <el-table-column label="鍏ュ簱鏃堕棿"
+                           prop="inboundTime"
+                           min-width="160"
+                           show-overflow-tooltip />
+          <el-table-column label="鍏ュ簱绫诲埆"
+                           prop="inboundCategory"
+                           min-width="100"
+                           show-overflow-tooltip />
+          <el-table-column label="娌瑰簱"
+                           prop="oilDepotName"
+                           min-width="130"
+                           show-overflow-tooltip />
+          <el-table-column label="鍌ㄧ綈鍙�"
+                           prop="tankNo"
+                           min-width="90"
+                           show-overflow-tooltip />
+          <el-table-column label="娌瑰搧"
+                           prop="productName"
+                           min-width="90"
+                           show-overflow-tooltip />
+          <el-table-column label="鍘熷巶鏁伴噺(鍚�)"
+                           prop="originalQuantity"
+                           min-width="110"
+                           show-overflow-tooltip />
+          <el-table-column label="瑙勬牸鍨嬪彿"
+                           prop="model"
+                           min-width="110"
+                           show-overflow-tooltip />
+          <el-table-column label="鎵瑰彿"
+                           prop="batchNo"
+                           min-width="140"
+                           show-overflow-tooltip />
+          <el-table-column label="鍗曚綅"
+                           prop="unit"
+                           min-width="70"
+                           show-overflow-tooltip />
+          <el-table-column label="鍏ュ簱鏁伴噺"
+                           prop="stockInNum"
+                           min-width="100"
+                           show-overflow-tooltip />
+          <el-table-column label="鍏ュ簱浜�"
+                           prop="createBy"
+                           min-width="90"
+                           show-overflow-tooltip />
+          <el-table-column label="鏉ユ簮"
+                           prop="recordType"
+                           min-width="90"
+                           show-overflow-tooltip>
+            <template #default="scope">
+              {{ getRecordType(scope.row.recordType) }}
+            </template>
+          </el-table-column>
+          <el-table-column v-if="showSourceOrderNoColumn"
+                           label="婧愬崟鍙�"
+                           min-width="150"
+                           prop="sourceOrderNo"
+                           show-overflow-tooltip>
+            <template #default="scope">
+              {{ formatSourceOrderNo(scope.row?.sourceOrderNo) }}
+            </template>
+          </el-table-column>
+          <el-table-column label="瀹℃壒鐘舵��"
+                           prop="approvalStatus"
+                           min-width="100"
+                           show-overflow-tooltip>
+            <template #default="scope">
+              <el-tag :type="getApprovalStatusTagType(scope.row.approvalStatus)"
+                      size="small">
+                {{ getApprovalStatusLabel(scope.row.approvalStatus) }}
+              </el-tag>
+            </template>
+          </el-table-column>
         </el-table-column>
-        <el-table-column v-if="showSourceOrderNoColumn"
-                         label="婧愬崟鍙�"
-                         width="150"
-                         prop="sourceOrderNo"
-                         show-overflow-tooltip>
-          <template #default="scope">
-            {{ formatSourceOrderNo(scope.row?.sourceOrderNo) }}
-          </template>
+        <el-table-column label="瀹㈡埛淇℃伅"
+                         align="center"
+                         :header-cell-style="groupHeaderStyle">
+          <el-table-column label="瀹㈡埛鍚嶇О"
+                           prop="customerName"
+                           min-width="160"
+                           show-overflow-tooltip />
+          <el-table-column label="瀹㈡埛瀵规帴浜�"
+                           prop="contactPerson"
+                           min-width="100"
+                           show-overflow-tooltip />
+          <el-table-column label="瀵规帴浜虹數璇�"
+                           prop="contactPhone"
+                           min-width="120"
+                           show-overflow-tooltip />
         </el-table-column>
-        <el-table-column label="瀹℃壒鐘舵��"
-                         prop="approvalStatus"
-                         show-overflow-tooltip>
-          <template #default="scope">
-            <el-tag :type="getApprovalStatusTagType(scope.row.approvalStatus)"
-                    size="small">
-              {{ getApprovalStatusLabel(scope.row.approvalStatus) }}
-            </el-tag>
-          </template>
+        <el-table-column label="鐗╂祦淇℃伅"
+                         align="center"
+                         :header-cell-style="groupHeaderStyle">
+          <el-table-column label="鍙告満濮撳悕"
+                           prop="driverName"
+                           min-width="100"
+                           show-overflow-tooltip />
+          <el-table-column label="鍙告満鐢佃瘽"
+                           prop="driverPhone"
+                           min-width="120"
+                           show-overflow-tooltip />
+          <el-table-column label="鎶艰繍鍛樺鍚�"
+                           prop="escortName"
+                           min-width="100"
+                           show-overflow-tooltip />
+          <el-table-column label="鎶艰繍鍛樼數璇�"
+                           prop="escortPhone"
+                           min-width="120"
+                           show-overflow-tooltip />
+          <el-table-column label="杞︾墝鍙�"
+                           prop="truckPlateNo"
+                           min-width="110"
+                           show-overflow-tooltip />
+          <el-table-column label="杞︽寕鐗屽彿"
+                           prop="trailerPlateNo"
+                           min-width="110"
+                           show-overflow-tooltip />
+        </el-table-column>
+        <el-table-column label="鍗告补鎿嶄綔淇℃伅"
+                         align="center"
+                         :header-cell-style="groupHeaderStyle">
+          <el-table-column label="杞︿綋/閾呭皝妫�楠�"
+                           prop="tankInspectionStatus"
+                           min-width="120"
+                           show-overflow-tooltip />
+          <el-table-column label="鍗歌溅楣や綅"
+                           prop="unloadingCranePosition"
+                           min-width="100"
+                           show-overflow-tooltip />
+          <el-table-column label="瀵嗗害"
+                           prop="density"
+                           min-width="80"
+                           show-overflow-tooltip />
+          <el-table-column label="鍗告补鎷嶇収"
+                           prop="unloadPhotos"
+                           align="center"
+                           min-width="90">
+            <template #default="scope">
+              <el-image v-if="toPhotoArray(scope.row.unloadPhotos).length"
+                        :src="getPhotoUrl(toPhotoArray(scope.row.unloadPhotos)[0])"
+                        :preview-src-list="getPhotoUrls(scope.row.unloadPhotos)"
+                        preview-teleported
+                        fit="cover"
+                        style="width: 40px; height: 40px; border-radius: 4px" />
+              <span v-else>--</span>
+            </template>
+          </el-table-column>
+        </el-table-column>
+        <el-table-column label="杩囩鏁版嵁"
+                         align="center"
+                         :header-cell-style="groupHeaderStyle">
+          <el-table-column label="姣涢噸(鍚�)"
+                           prop="grossWeight"
+                           min-width="90"
+                           show-overflow-tooltip />
+          <el-table-column label="鐨噸(鍚�)"
+                           prop="tareWeight"
+                           min-width="90"
+                           show-overflow-tooltip />
+          <el-table-column label="鍑�閲�(鍚�)"
+                           prop="netWeight"
+                           min-width="90"
+                           show-overflow-tooltip />
+          <el-table-column label="浜忛噺(鍚�)"
+                           prop="lossQuantity"
+                           min-width="90"
+                           show-overflow-tooltip />
+          <el-table-column label="瀹為檯鍏ュ簱浣撶Н(鍗�)"
+                           prop="actualVolume"
+                           min-width="130"
+                           show-overflow-tooltip />
+          <el-table-column label="纾呭崟"
+                           prop="poundPhotos"
+                           align="center"
+                           min-width="90">
+            <template #default="scope">
+              <el-image v-if="toPhotoArray(scope.row.poundPhotos).length"
+                        :src="getPhotoUrl(toPhotoArray(scope.row.poundPhotos)[0])"
+                        :preview-src-list="getPhotoUrls(scope.row.poundPhotos)"
+                        preview-teleported
+                        fit="cover"
+                        style="width: 40px; height: 40px; border-radius: 4px" />
+              <span v-else>--</span>
+            </template>
+          </el-table-column>
         </el-table-column>
       </el-table>
       <pagination v-show="total > 0"
@@ -356,6 +497,40 @@
       });
   };
 
+  // 鍒嗙粍鐖惰〃澶存牱寮忥細鍖哄垎鍚勫垎绫�
+  const groupHeaderStyle = {
+    background: "#e8f3ff",
+    color: "#1d6fd8",
+    fontWeight: "700",
+    fontSize: "13px",
+  };
+
+  // 鐓х墖瀛楁鍚庣瀛樼殑鏄� JSON 瀛楃涓诧紝鍑哄弬闇�鑷瑙f瀽
+  const toPhotoArray = value => {
+    if (!value) {
+      return [];
+    }
+    if (Array.isArray(value)) {
+      return value;
+    }
+    if (typeof value === "string") {
+      try {
+        const parsed = JSON.parse(value);
+        return Array.isArray(parsed) ? parsed : [];
+      } catch (e) {
+        return [];
+      }
+    }
+    return [];
+  };
+
+  const getPhotoUrl = photo =>
+    typeof photo === "string" ? photo : photo?.url || photo?.previewURL || "";
+
+  // 鍥剧墖鍒楋細鍙栧叏閮ㄥ湴鍧�鐢ㄤ簬棰勮
+  const getPhotoUrls = photos =>
+    toPhotoArray(photos).map(getPhotoUrl).filter(Boolean);
+
   // 鑾峰彇鏉ユ簮绫诲瀷閫夐」
   const fetchStockRecordTypeOptions = () => {
     if (props.type === "0") {
diff --git a/src/views/inventoryManagement/stockManagement/BatchNoQtyDetail.vue b/src/views/inventoryManagement/stockManagement/BatchNoQtyDetail.vue
index c131ec2..8be2811 100644
--- a/src/views/inventoryManagement/stockManagement/BatchNoQtyDetail.vue
+++ b/src/views/inventoryManagement/stockManagement/BatchNoQtyDetail.vue
@@ -21,7 +21,7 @@
               height="100%"
             >
           <el-table-column
-            label="浜у搧鍚嶇О"
+            label="娌瑰搧"
             prop="productName"
             show-overflow-tooltip
           />
@@ -34,18 +34,8 @@
             show-overflow-tooltip
           />
           <el-table-column
-            label="涓嶅悎鏍煎簱瀛樻暟閲�"
-            prop="unQualifiedQuantity"
-            show-overflow-tooltip
-          />
-          <el-table-column
             label="鍚堟牸鍐荤粨鏁伴噺"
             prop="qualifiedLockedQuantity"
-            show-overflow-tooltip
-          />
-          <el-table-column
-            label="涓嶅悎鏍煎喕缁撴暟閲�"
-            prop="unQualifiedLockedQuantity"
             show-overflow-tooltip
           />
           <el-table-column
@@ -111,7 +101,7 @@
           <el-table-column label="鍏ュ簱淇℃伅"
                            align="center"
                            :header-cell-style="groupHeaderStyle">
-            <el-table-column label="娌瑰搧" prop="oilProduct" min-width="90" show-overflow-tooltip />
+            <el-table-column label="娌瑰搧" prop="productName" min-width="90" show-overflow-tooltip />
             <el-table-column label="鍏ュ簱鍚嶇О" prop="oilDepotName" min-width="130" show-overflow-tooltip />
             <el-table-column label="鍏ュ簱绫诲埆" prop="inboundCategory" min-width="100" show-overflow-tooltip />
             <el-table-column label="鍌ㄧ綈鍙�" prop="tankNo" min-width="100" show-overflow-tooltip />
@@ -191,7 +181,7 @@
             <el-table-column label="鍌ㄥ簱鍚嶇О" prop="outOilDepotName" min-width="130" show-overflow-tooltip />
             <el-table-column label="鍌ㄧ綈鍙�" prop="outTankNo" min-width="100" show-overflow-tooltip />
             <el-table-column label="鍑哄簱鏃ユ湡" prop="outDate" min-width="110" show-overflow-tooltip />
-            <el-table-column label="娌瑰搧" prop="outOilProduct" min-width="90" show-overflow-tooltip />
+            <el-table-column label="娌瑰搧" prop="productName" min-width="90" show-overflow-tooltip />
             <el-table-column label="鍑哄簱鍚ㄤ綅(鍚�)" prop="outTonnage" min-width="110" show-overflow-tooltip />
             <el-table-column label="瀹㈡埛鍚嶇О" prop="outCustomerName" min-width="120" show-overflow-tooltip />
             <el-table-column label="瀹㈡埛瀵规帴浜�" prop="outContactPerson" min-width="100" show-overflow-tooltip />
diff --git a/src/views/inventoryManagement/stockManagement/OilStockInDialog.vue b/src/views/inventoryManagement/stockManagement/OilStockInDialog.vue
index 8433960..722db7e 100644
--- a/src/views/inventoryManagement/stockManagement/OilStockInDialog.vue
+++ b/src/views/inventoryManagement/stockManagement/OilStockInDialog.vue
@@ -151,22 +151,10 @@
           <el-col :span="12">
             <el-form-item label="娌瑰搧"
                           prop="oilProduct"
-                          :rules="isOilProduct ? [
-                {
-                required: true,
-                message: '璇烽�夋嫨娌瑰搧',
-                trigger: 'change',
-              }
-            ] : []">
-              <el-input v-if="isOilProduct"
-                        :model-value="formState.oilProduct"
+                          :rules="[{ required: true, message: '璇烽�夋嫨娌瑰搧', trigger: 'change' }]">
+              <el-input :model-value="formState.oilProduct"
                         readonly
                         placeholder="--" />
-              <el-select v-else
-                         v-model="formState.oilProduct"
-                         placeholder="璇烽�夋嫨"
-                         disabled
-                         style="width: 100%" />
             </el-form-item>
           </el-col>
           <el-col :span="12">
@@ -461,7 +449,6 @@
   import { allOilDepot } from "@/api/basicData/oilDepot.js";
   import { allTankInfo } from "@/api/basicData/tankInfo.js";
   import { listCustomer } from "@/api/basicData/customer.js";
-  import { productTreeList } from "@/api/basicData/product.js";
 
   const props = defineProps({
     visible: {
@@ -507,8 +494,6 @@
   const oilDepotList = ref([]);
   const tankList = ref([]);
   const customerList = ref([]);
-  const oilProductOptions = ref([]);
-
   const isShow = computed({
     get() {
       return props.visible;
@@ -517,32 +502,6 @@
       emit("update:visible", val);
     },
   });
-
-  // 鍦ㄤ骇鍝佹爲涓煡鎵�"娌瑰搧"鍒嗙被鑺傜偣
-  const findOilNode = nodes => {
-    for (const node of nodes || []) {
-      if (node.productName === "娌瑰搧") {
-        return node;
-      }
-      if (node.children && node.children.length) {
-        const found = findOilNode(node.children);
-        if (found) {
-          return found;
-        }
-      }
-    }
-    return null;
-  };
-
-  // 鎵�閫夊晢鍝佸悕绉板懡涓殑娌瑰搧閫夐」锛堟补鍝佽妭鐐瑰瓙椤癸紝鏉ヨ嚜浜у搧缁存姢妯″潡锛�
-  const matchedOilOption = computed(() =>
-    oilProductOptions.value.find(
-      item => item.productName === formState.value.productName
-    )
-  );
-
-  // 鍙湁閫変腑娌瑰搧瀛楁閫夐」閲屾湁鐨勫叿浣撴补鍝佹墠鍚敤娌瑰搧瀛楁锛�"娌瑰搧"澶х被鏈韩涓嶅惎鐢�
-  const isOilProduct = computed(() => !!matchedOilOption.value);
 
   // 鍑�閲�(鍚�) = 姣涢噸 - 鐨噸
   const netWeight = computed(() => {
@@ -609,10 +568,9 @@
       formState.value.productModelName = product.model;
       formState.value.productModelId = product.id;
       formState.value.unit = product.unit;
-      // 娌瑰搧閫夐」涓庡晢鍝佸悕绉板悓姝ワ細鍛戒腑娌瑰搧閫夐」鍒欒嚜鍔ㄥ甫鍑鸿娌瑰搧锛屾湭鍛戒腑鍒欐竻绌哄苟绂佺敤
-      formState.value.oilProduct = matchedOilOption.value
-        ? product.productName
-        : undefined;
+      // 鏈鎴枫�屾补鍝併�嶅氨鏄骇鍝佸悕绉帮紙搴撳瓨鏄庣粏/鍑哄簱鍙拌处鐨勬补鍝佸垪缁戠殑閮芥槸 productName锛夛紝
+      // 鐩存帴鍙栨墍閫変骇鍝佸悕锛屼笉鍐嶅幓浜у搧鏍戦噷姣斿锛岄伩鍏嶆瘮瀵逛笉涓婃椂娌瑰搧鏍忕┖鐧�
+      formState.value.oilProduct = product.productName || undefined;
       showProductSelectDialog.value = false;
       // 瑙﹀彂琛ㄥ崟楠岃瘉鏇存柊
       proxy.$refs["formRef"]?.validateField("productModelId");
@@ -652,10 +610,6 @@
     });
     listCustomer({ current: 1, size: 1000, type: 0 }).then(res => {
       customerList.value = res?.data?.records || [];
-    });
-    productTreeList().then(res => {
-      const oilNode = findOilNode(res);
-      oilProductOptions.value = oilNode?.children || [];
     });
   });
 </script>
diff --git a/src/views/inventoryManagement/stockManagement/OilStockOutDialog.vue b/src/views/inventoryManagement/stockManagement/OilStockOutDialog.vue
index c3a7865..0b6244a 100644
--- a/src/views/inventoryManagement/stockManagement/OilStockOutDialog.vue
+++ b/src/views/inventoryManagement/stockManagement/OilStockOutDialog.vue
@@ -44,7 +44,7 @@
         </el-row>
         <div class="form-section-title">鍑哄簱淇℃伅</div>
         <el-row :gutter="30">
-          <el-col :span="12">
+          <el-col :span="8">
             <el-form-item label="鍑哄簱绫诲埆"
                           prop="outCategory"
                           :rules="[{ required: true, message: '璇烽�夋嫨鍑哄簱绫诲埆', trigger: 'change' }]">
@@ -61,7 +61,25 @@
               </el-select>
             </el-form-item>
           </el-col>
-          <el-col :span="12">
+          <el-col :span="8">
+            <el-form-item label="鍑哄簱鎵规"
+                          prop="batchNo"
+                          :rules="isSalesOut
+                ? [{ required: true, message: '閿�鍞被鍑哄簱蹇呴』閫夋嫨鍑哄簱鎵规', trigger: 'change' }]
+                : []">
+              <el-select v-model="formState.batchNo"
+                         placeholder="璇烽�夋嫨"
+                         clearable
+                         filterable
+                         style="width: 100%">
+                <el-option v-for="item in batchNoOptions"
+                           :key="item"
+                           :label="item"
+                           :value="item" />
+              </el-select>
+            </el-form-item>
+          </el-col>
+          <el-col :span="8">
             <el-form-item label="鍌ㄥ簱鍚嶇О"
                           prop="oilDepotId"
                           :rules="[{ required: true, message: '璇烽�夋嫨鍌ㄥ簱鍚嶇О', trigger: 'change' }]">
@@ -130,22 +148,10 @@
           <el-col :span="12">
             <el-form-item label="娌瑰搧"
                           prop="oilProduct"
-                          :rules="isOilProduct ? [
-                {
-                required: true,
-                message: '璇烽�夋嫨娌瑰搧',
-                trigger: 'change',
-              }
-            ] : []">
-              <el-input v-if="isOilProduct"
-                        :model-value="formState.oilProduct"
+                          :rules="[{ required: true, message: '璇烽�夋嫨娌瑰搧', trigger: 'change' }]">
+              <el-input :model-value="formState.oilProduct"
                         readonly
                         placeholder="--" />
-              <el-select v-else
-                         v-model="formState.oilProduct"
-                         placeholder="璇烽�夋嫨"
-                         disabled
-                         style="width: 100%" />
             </el-form-item>
           </el-col>
           <el-col :span="12">
@@ -317,6 +323,45 @@
         <div class="form-section-title">鐗╂祦淇℃伅</div>
         <el-row :gutter="30">
           <el-col :span="12">
+            <el-form-item label="杞﹁締"
+                          prop="vehicleId"
+                          :rules="isSalesOut
+                ? [{ required: true, message: '閿�鍞被鍑哄簱蹇呴』閫夋嫨杞﹁締', trigger: 'change' }]
+                : []">
+              <el-select v-model="formState.vehicleId"
+                         placeholder="璇烽�夋嫨"
+                         clearable
+                         filterable
+                         popper-class="vehicle-select-popper"
+                         style="width: 100%"
+                         @change="vehicleChange">
+                <el-option v-for="item in vehicleList"
+                           :key="item.id"
+                           :label="item.plateNumber"
+                           :value="item.id">
+                  <div class="vehicle-option">
+                    <div class="vehicle-option-title">{{ item.plateNumber }}</div>
+                    <div class="vehicle-option-line">榛樿鍙告満锛歿{ item.driverName || '--' }}</div>
+                    <div class="vehicle-option-line">鍙告満鐢佃瘽锛歿{ item.driverPhone || '--' }}</div>
+                    <div class="vehicle-option-line">鏍稿畾杞介噸(鍚�)锛歿{ item.loadCapacity ?? '--' }}</div>
+                  </div>
+                </el-option>
+              </el-select>
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="杞︽寕鐗屽彿"
+                          prop="trailerPlateNo"
+                          :rules="[{ required: true, message: '璇疯緭鍏ヨ溅鎸傜墝鍙�', trigger: 'blur' }]">
+              <el-input v-model="formState.trailerPlateNo"
+                        :readonly="!!formState.vehicleId"
+                        placeholder="璇疯緭鍏�"
+                        clearable />
+            </el-form-item>
+          </el-col>
+        </el-row>
+        <el-row :gutter="30">
+          <el-col :span="12">
             <el-form-item label="鍙告満濮撳悕"
                           prop="driverName"
                           :rules="[{ required: true, message: '璇疯緭鍏ュ徃鏈哄鍚�', trigger: 'blur' }]">
@@ -365,23 +410,16 @@
             </el-form-item>
           </el-col>
         </el-row>
-        <el-row :gutter="30">
-          <el-col :span="12">
-            <el-form-item label="杞︾墝鍙�"
-                          prop="truckPlateNo"
-                          :rules="[{ required: true, message: '璇疯緭鍏ヨ溅鐗屽彿', trigger: 'blur' }]">
-              <el-input v-model="formState.truckPlateNo"
-                        placeholder="璇疯緭鍏�"
-                        clearable />
-            </el-form-item>
-          </el-col>
-          <el-col :span="12">
-            <el-form-item label="杞︽寕鐗屽彿"
-                          prop="trailerPlateNo"
-                          :rules="[{ required: true, message: '璇疯緭鍏ヨ溅鎸傜墝鍙�', trigger: 'blur' }]">
-              <el-input v-model="formState.trailerPlateNo"
-                        placeholder="璇疯緭鍏�"
-                        clearable />
+        <el-row :gutter="30"
+                v-if="isSalesOut">
+          <el-col :span="24">
+            <el-form-item label="鍙敤閲�">
+              <div class="available-qty-tip">
+                <span>涓婃鍓╀綑(鍚�)锛歿{ availableQtyText.lastResidualOil }}</span>
+                <span>褰撳墠搴撳瓨(鍚�)锛歿{ availableQtyText.stockQuantity }}</span>
+                <span class="available-qty-strong">鍙敤閲�(鍚�)锛歿{ availableQtyText.availableQty }}</span>
+                <span class="available-qty-rule">鍙敤閲� = 涓婃鍓╀綑 + 褰撳墠搴撳瓨</span>
+              </div>
             </el-form-item>
           </el-col>
         </el-row>
@@ -402,14 +440,18 @@
 </template>
 
 <script setup>
-  import { ref, computed, getCurrentInstance, onMounted } from "vue";
+  import { ref, computed, watch, getCurrentInstance, onMounted } from "vue";
   import ProductSelectDialog from "@/views/basicData/product/ProductSelectDialog.vue";
   import ImageUpload from "@/components/AttachmentUpload/image/index.vue";
-  import { addOilOutRecordOnly } from "@/api/inventoryManagement/stockInventory.js";
+  import {
+    addOilOutRecordOnly,
+    getStockInventoryBatchNoQty,
+  } from "@/api/inventoryManagement/stockInventory.js";
+  import { getOilOutAvailableQty } from "@/api/inventoryManagement/stockOut.js";
   import { allOilDepot } from "@/api/basicData/oilDepot.js";
   import { allTankInfo } from "@/api/basicData/tankInfo.js";
+  import { allVehicle } from "@/api/basicData/vehicle.js";
   import { listCustomer } from "@/api/basicData/customer.js";
-  import { productTreeList } from "@/api/basicData/product.js";
 
   const props = defineProps({
     visible: {
@@ -427,6 +469,7 @@
     model: "",
     unit: "",
     outCategory: undefined,
+    batchNo: undefined,
     oilDepotId: undefined,
     oilDepotName: "",
     tankId: undefined,
@@ -448,6 +491,7 @@
     driverPhone: "",
     escortName: "",
     escortPhone: "",
+    vehicleId: undefined,
     truckPlateNo: "",
     trailerPlateNo: "",
   });
@@ -457,34 +501,67 @@
   const oilDepotList = ref([]);
   const tankList = ref([]);
   const customerList = ref([]);
-  const oilProductOptions = ref([]);
+  const vehicleList = ref([]);
   const showProductSelectDialog = ref(false);
+  // 鍑哄簱鎵规鍊欓�夊彇璇ヨ鏍肩殑鍏ュ簱鎵规
+  const batchNoOptions = ref([]);
+  // 閿�鍞被鍑哄簱鐨勫彲鐢ㄩ噺鎻愮ず锛堜笂娆″墿浣� + 褰撳墠搴撳瓨锛�
+  const availableQty = ref(null);
 
-  // 鍦ㄤ骇鍝佹爲涓煡鎵�"娌瑰搧"鍒嗙被鑺傜偣
-  const findOilNode = nodes => {
-    for (const node of nodes || []) {
-      if (node.productName === "娌瑰搧") {
-        return node;
-      }
-      if (node.children && node.children.length) {
-        const found = findOilNode(node.children);
-        if (found) {
-          return found;
-        }
-      }
+  const fetchBatchNoOptions = () => {
+    batchNoOptions.value = [];
+    const productModelId = formState.value.productModelId;
+    if (!productModelId) {
+      return;
     }
-    return null;
+    getStockInventoryBatchNoQty({
+      current: 1,
+      size: 200,
+      productModelId,
+    }).then(res => {
+      const records = res?.data?.records || [];
+      batchNoOptions.value = [
+        ...new Set(records.map(item => item.batchNo).filter(Boolean)),
+      ];
+    });
   };
 
-  // 鎵�閫夊晢鍝佸悕绉板懡涓殑娌瑰搧閫夐」锛堟补鍝佽妭鐐瑰瓙椤癸紝鏉ヨ嚜浜у搧缁存姢妯″潡锛�
-  const matchedOilOption = computed(() =>
-    oilProductOptions.value.find(
-      item => item.productName === formState.value.productName
-    )
-  );
+  // 閿�鍞被鍑哄簱蹇呴』缁欏嚭搴撴壒娆★紙鍚庣鏂板鏃跺嵆鏍¢獙锛屼笖瀹℃壒閫氳繃浼氭寜鎵规鎵e簱瀛橈級
+  const isSalesOut = computed(() => formState.value.outCategory === "閿�鍞�");
 
-  // 鍙湁閫変腑娌瑰搧瀛楁閫夐」閲屾湁鐨勫叿浣撴补鍝佹墠鍚敤娌瑰搧瀛楁锛�"娌瑰搧"澶х被鏈韩涓嶅惎鐢�
-  const isOilProduct = computed(() => !!matchedOilOption.value);
+  // 鍙敤閲忔彁绀猴細杞﹁締 + 瑙勬牸锛�+鎵规锛夌‘瀹氬悗鍚戝悗绔彇銆屼笂娆″墿浣� / 褰撳墠搴撳瓨 / 鍙敤閲忋��
+  const fetchAvailableQty = () => {
+    availableQty.value = null;
+    const { vehicleId, productModelId, batchNo } = formState.value;
+    if (!isSalesOut.value || !vehicleId || !productModelId) {
+      return;
+    }
+    getOilOutAvailableQty({ vehicleId, productModelId, batchNo })
+      .then(res => {
+        availableQty.value = res?.data || null;
+      })
+      .catch(() => {
+        availableQty.value = null;
+      });
+  };
+
+  const availableQtyText = computed(() => ({
+    lastResidualOil: availableQty.value?.lastResidualOil ?? "--",
+    stockQuantity: availableQty.value?.stockQuantity ?? "--",
+    availableQty: availableQty.value?.availableQty ?? "--",
+  }));
+
+  watch(
+    () => [
+      formState.value.outCategory,
+      formState.value.vehicleId,
+      formState.value.productModelId,
+      formState.value.batchNo,
+    ],
+    () => {
+      fetchAvailableQty();
+    }
+  );
 
   const isShow = computed({
     get() {
@@ -549,10 +626,11 @@
       formState.value.model = product.model;
       formState.value.productModelId = product.id;
       formState.value.unit = product.unit;
-      // 娌瑰搧閫夐」涓庡晢鍝佸悕绉板悓姝ワ細鍛戒腑娌瑰搧閫夐」鍒欒嚜鍔ㄥ甫鍑鸿娌瑰搧锛屾湭鍛戒腑鍒欐竻绌哄苟绂佺敤
-      formState.value.oilProduct = matchedOilOption.value
-        ? product.productName
-        : undefined;
+      // 鏈鎴枫�屾补鍝併�嶅氨鏄骇鍝佸悕绉帮紙搴撳瓨鏄庣粏/鍑哄簱鍙拌处鐨勬补鍝佸垪缁戠殑閮芥槸 productName锛夛紝
+      // 鐩存帴鍙栨墍閫変骇鍝佸悕锛屼笉鍐嶅幓浜у搧鏍戦噷姣斿锛岄伩鍏嶆瘮瀵逛笉涓婃椂娌瑰搧鏍忕┖鐧�
+      formState.value.oilProduct = product.productName || undefined;
+      formState.value.batchNo = undefined;
+      fetchBatchNoOptions();
       showProductSelectDialog.value = false;
       proxy.$refs["formRef"]?.validateField("productModelId");
     }
@@ -586,6 +664,21 @@
     }
   };
 
+  // 杞﹁締閫夋嫨鏀瑰彉锛氳溅鐗屽彿銆佽溅鎸傜墝鍙蜂笌鍙告満淇℃伅鐢辫溅杈嗕富鏁版嵁甯﹀嚭锛屽嚭搴撴椂鍙告満鍙墜鍔ㄨ鐩�
+  const vehicleChange = id => {
+    const vehicle = vehicleList.value.find(item => item.id === id);
+    if (vehicle) {
+      formState.value.truckPlateNo = vehicle.plateNumber || "";
+      // 杞︽寕鐗屽彿涓庤溅鐗屽彿鏄悓涓�涓墝锛岄�変簡杞﹁締灏卞甫鍑哄苟缃负鍙锛岄伩鍏嶆墜濉嚭涓や釜涓嶄竴鑷寸殑鍊�
+      formState.value.trailerPlateNo = vehicle.plateNumber || "";
+      formState.value.driverName = vehicle.driverName || "";
+      formState.value.driverPhone = vehicle.driverPhone || "";
+    } else {
+      formState.value.truckPlateNo = "";
+      formState.value.trailerPlateNo = "";
+    }
+  };
+
   const handleSubmit = () => {
     proxy.$refs["formRef"].validate(valid => {
       if (valid) {
@@ -615,15 +708,14 @@
     allOilDepot().then(res => {
       oilDepotList.value = res?.data || [];
     });
-    productTreeList().then(res => {
-      const oilNode = findOilNode(res);
-      oilProductOptions.value = oilNode?.children || [];
-    });
     allTankInfo().then(res => {
       tankList.value = res?.data || [];
     });
     listCustomer({ current: 1, size: 1000, type: 0 }).then(res => {
       customerList.value = res?.data?.records || [];
+    });
+    allVehicle().then(res => {
+      vehicleList.value = res?.data || [];
     });
   });
 </script>
@@ -671,6 +763,48 @@
     }
 
     .tank-option-line {
+      font-size: 12px;
+      color: #909399;
+      line-height: 1.8;
+    }
+  }
+
+  // 鍙敤閲忔彁绀猴細涓婃鍓╀綑 + 褰撳墠搴撳瓨 = 鍙敤閲�
+  .available-qty-tip {
+    display: flex;
+    flex-wrap: wrap;
+    align-items: center;
+    gap: 6px 20px;
+    width: 100%;
+    padding: 6px 14px;
+    font-size: 13px;
+    color: #303133;
+    background: rgba(64, 158, 255, 0.08);
+    border-left: 3px solid #409eff;
+    border-radius: 3px;
+
+    .available-qty-strong {
+      font-weight: 600;
+      color: #1d6fd8;
+    }
+
+    .available-qty-rule {
+      color: #909399;
+    }
+  }
+
+  // 杞﹁締涓嬫媺閫夐」锛氬皬鍗$墖鏍峰紡
+  .vehicle-option {
+    padding: 8px 10px;
+
+    .vehicle-option-title {
+      font-size: 14px;
+      font-weight: 600;
+      color: #303133;
+      margin-bottom: 4px;
+    }
+
+    .vehicle-option-line {
       font-size: 12px;
       color: #909399;
       line-height: 1.8;
@@ -737,6 +871,26 @@
     }
   }
 
+  // 杞﹁締涓嬫媺闈㈡澘锛坆ody 涓嬶紝闇�鍏ㄥ眬鏍峰紡锛�
+  .vehicle-select-popper {
+    .el-select-dropdown__item {
+      height: auto;
+      line-height: normal;
+      padding: 4px 0;
+    }
+
+    .vehicle-option {
+      border: 1px solid #e4e7ed;
+      border-radius: 6px;
+      background-color: #fafbfc;
+
+      &:hover {
+        border-color: #409eff;
+        background-color: #f0f7ff;
+      }
+    }
+  }
+
   // 瀹㈡埛鍚嶇О涓嬫媺闈㈡澘锛坆ody 涓嬶紝闇�鍏ㄥ眬鏍峰紡锛�
   .customer-select-popper {
     .el-select-dropdown__item {
diff --git a/src/views/inventoryManagement/stockManagement/Record.vue b/src/views/inventoryManagement/stockManagement/Record.vue
index bdd00b4..7799ce1 100644
--- a/src/views/inventoryManagement/stockManagement/Record.vue
+++ b/src/views/inventoryManagement/stockManagement/Record.vue
@@ -3,37 +3,34 @@
     <div class="search_form mb10">
       <el-form ref="searchFormRef"
                :model="searchForm"
-               class="demo-form-inline">
+               class="demo-form-inline"
+               style="width: 100%">
         <el-row :gutter="20">
-          <el-col :span="4">
+          <el-col :span="6">
             <el-form-item label="浜у搧澶х被"
                           prop="productName">
               <el-input v-model="searchForm.productName"
-                        style="width: 240px"
                         placeholder="璇疯緭鍏�"
                         clearable />
             </el-form-item>
           </el-col>
-          <el-col :span="4">
+          <el-col :span="6">
             <el-form-item label="瑙勬牸鍨嬪彿"
                           prop="model">
               <el-input v-model="searchForm.model"
-                        style="width: 240px"
                         placeholder="璇疯緭鍏�"
                         clearable />
             </el-form-item>
           </el-col>
-          <el-col :span="4">
+          <el-col :span="6">
             <el-form-item label="鎵瑰彿"
                           prop="batchNo">
               <el-input v-model="searchForm.batchNo"
-                        style="width: 240px"
                         placeholder="璇疯緭鍏�"
                         clearable />
             </el-form-item>
           </el-col>
-          <!-- 鎸夐挳 -->
-          <el-col :span="4">
+          <el-col :span="6">
             <el-form-item>
               <el-button type="primary"
                          @click="getList">
@@ -46,23 +43,26 @@
           </el-col>
         </el-row>
       </el-form>
-      <div style="display: flex; gap: 10px; flex-wrap: nowrap;">
-        <el-button type="primary"
-                   @click="isShowNewModal = true">鏂板搴撳瓨</el-button>
-        <el-button type="primary"
-                   @click="isShowOilInModal = true">鏂板娌瑰搧鍏ュ簱</el-button>
-        <el-button type="primary"
-                   @click="isShowOilOutModal = true">鏂板娌瑰搧鍑哄簱</el-button>
-        <el-button type="info"
-                   plain
-                   icon="Upload"
-                   @click="isShowImportModal = true">
-          瀵煎叆搴撳瓨
-        </el-button>
-        <el-button @click="handleOut">瀵煎嚭</el-button>
-      </div>
     </div>
     <div class="table_list">
+      <div class="actions">
+        <div></div>
+        <div>
+          <el-button type="primary"
+                     @click="isShowNewModal = true">鏂板搴撳瓨</el-button>
+          <el-button type="primary"
+                     @click="isShowOilInModal = true">鏂板娌瑰搧鍏ュ簱</el-button>
+          <el-button type="primary"
+                     @click="isShowOilOutModal = true">鏂板娌瑰搧鍑哄簱</el-button>
+          <el-button type="info"
+                     plain
+                     icon="Upload"
+                     @click="isShowImportModal = true">
+            瀵煎叆搴撳瓨
+          </el-button>
+          <el-button @click="handleOut">瀵煎嚭</el-button>
+        </div>
+      </div>
       <el-table :data="tableData"
                 border
                 v-loading="tableLoading"
@@ -71,18 +71,30 @@
                 :row-key="(row, index) => index"
                 style="width: 100%"
                 :row-class-name="tableRowClassName"
-                height="calc(100vh - 18.5em)">
+                :span-method="spanMethod"
+                height="calc(100vh - 21em)">
         <el-table-column align="center"
                          type="selection"
+                         :selectable="isRowSelectable"
                          width="55" />
         <el-table-column align="center"
                          label="搴忓彿"
                          type="index"
+                         :index="indexMethod"
                          width="60" />
         <el-table-column label="浜у搧鍚嶇О"
                          prop="productName"
-                         min-width="120"
-                         show-overflow-tooltip />
+                         min-width="120">
+          <template #default="scope">
+            <div v-if="scope.row.__isGroup"
+                 class="tank-group-band">
+              <span class="tank-group-band__name">鍌ㄧ綈鍙� {{ scope.row.tankNo || "鏈垎閰�" }}</span>
+              <span class="tank-group-band__stat">鍚堟牸 {{ scope.row.qualifiedQuantity }}</span>
+              <span class="tank-group-band__stat">鍐荤粨 {{ scope.row.qualifiedLockedQuantity }}</span>
+            </div>
+            <span v-else>{{ scope.row.productName }}</span>
+          </template>
+        </el-table-column>
         <el-table-column label="瑙勬牸鍨嬪彿"
                          prop="model"
                          min-width="120"
@@ -95,30 +107,26 @@
                          prop="batchNo"
                          min-width="150"
                          show-overflow-tooltip />
+        <el-table-column label="鍌ㄧ綈鍙�"
+                         prop="tankNo"
+                         min-width="100"
+                         show-overflow-tooltip />
         <el-table-column label="鍚堟牸搴撳瓨鏁伴噺"
                          prop="qualifiedQuantity"
                          min-width="110"
-                         show-overflow-tooltip />
-        <el-table-column label="涓嶅悎鏍煎簱瀛樻暟閲�"
-                         prop="unQualifiedQuantity"
-                         min-width="120"
                          show-overflow-tooltip />
         <el-table-column label="鍚堟牸鍐荤粨鏁伴噺"
                          prop="qualifiedLockedQuantity"
                          min-width="110"
                          show-overflow-tooltip />
-        <el-table-column label="涓嶅悎鏍煎喕缁撴暟閲�"
-                         prop="unQualifiedLockedQuantity"
-                         min-width="120"
-                         show-overflow-tooltip />
         <el-table-column label="搴撳瓨棰勮鏁伴噺"
                          prop="warnNum"
                          min-width="110"
                          show-overflow-tooltip />
-        <el-table-column label="澶囨敞"
-                         prop="remark"
-                         min-width="150"
-                         show-overflow-tooltip />
+<!--        <el-table-column label="澶囨敞"-->
+<!--                         prop="remark"-->
+<!--                         min-width="150"-->
+<!--                         show-overflow-tooltip />-->
         <el-table-column label="鏈�杩戞洿鏂版椂闂�"
                          prop="updateTime"
                          min-width="160"
@@ -179,7 +187,7 @@
 
 <script setup>
   import pagination from "@/components/PIMTable/Pagination.vue";
-  import { ref, reactive, toRefs, onMounted, getCurrentInstance } from "vue";
+  import { ref, reactive, toRefs, computed, onMounted, getCurrentInstance } from "vue";
   import { ElMessage, ElMessageBox } from "element-plus";
   import { getStockInventoryListPageCombined } from "@/api/inventoryManagement/stockInventory.js";
   const props = defineProps({
@@ -187,6 +195,10 @@
       type: Number,
       required: true,
       default: 0,
+    },
+    productName: {
+      type: String,
+      default: "",
     },
   });
 
@@ -221,6 +233,72 @@
     size: 100,
   });
   const total = ref(0);
+  // 鍌ㄧ綈鍙峰垎绫昏鍗犳弧鏁磋锛屾槑缁嗚姝e父娓叉煋
+  const TABLE_COLUMN_COUNT = 13;
+  const GROUP_ROW_LEAD_COLUMNS = 2; // 閫夋嫨鍒� + 搴忓彿鍒�
+  const isRowSelectable = row => !row?.__isGroup;
+  // 鍙湁鎴愬搧銆佸師鏂欎袱绫讳細鎸夊偍缃愬垎缃愬瓨鏀撅紝鍏朵綑澶х被涓嶅仛鍌ㄧ綈鍙峰垎缁�
+  const TANK_GROUP_CATEGORIES = ["鎴愬搧", "鍘熸枡"];
+  const shouldGroupByTank = computed(() =>
+    TANK_GROUP_CATEGORIES.includes(props.productName)
+  );
+  const sumBy = (rows, key) =>
+    rows.reduce((acc, row) => acc + Number(row[key] || 0), 0);
+  const buildGroupedRows = rows => {
+    const groups = new Map();
+    rows.forEach(row => {
+      const tankNo = row.tankNo || "";
+      if (!groups.has(tankNo)) {
+        groups.set(tankNo, []);
+      }
+      groups.get(tankNo).push(row);
+    });
+    const sortedTankNos = [...groups.keys()].sort((a, b) => {
+      if (!a) return 1;
+      if (!b) return -1;
+      return a.localeCompare(b, "zh-CN", { numeric: true });
+    });
+    return sortedTankNos.flatMap(tankNo => {
+      const groupRows = groups.get(tankNo);
+      return [
+        {
+          __isGroup: true,
+          tankNo,
+          qualifiedQuantity: sumBy(groupRows, "qualifiedQuantity"),
+          qualifiedLockedQuantity: sumBy(groupRows, "qualifiedLockedQuantity"),
+        },
+        ...groupRows,
+      ];
+    });
+  };
+  const spanMethod = ({ row, columnIndex }) => {
+    if (!row?.__isGroup) {
+      return { rowspan: 1, colspan: 1 };
+    }
+    if (columnIndex === 0) {
+      return { rowspan: 1, colspan: GROUP_ROW_LEAD_COLUMNS };
+    }
+    if (columnIndex === GROUP_ROW_LEAD_COLUMNS) {
+      return {
+        rowspan: 1,
+        colspan: TABLE_COLUMN_COUNT - GROUP_ROW_LEAD_COLUMNS,
+      };
+    }
+    return { rowspan: 0, colspan: 0 };
+  };
+  // 搴忓彿鍙鏄庣粏琛岃繛缁紪鍙凤紝鍒嗙被琛岀暀绌�
+  const indexMethod = index => {
+    if (tableData.value[index]?.__isGroup) {
+      return "";
+    }
+    let count = 0;
+    for (let i = 0; i <= index; i++) {
+      if (!tableData.value[i]?.__isGroup) {
+        count += 1;
+      }
+    }
+    return count;
+  };
   // 鏄惁鏄剧ず鏂板寮规
   const isShowNewModal = ref(false);
   // 鏄惁鏄剧ず娌瑰搧鍏ュ簱寮规
@@ -270,7 +348,9 @@
     getStockInventoryListPageCombined({ ...searchForm.value, ...page })
       .then(res => {
         tableLoading.value = false;
-        tableData.value = res.data.records;
+        tableData.value = shouldGroupByTank.value
+          ? buildGroupedRows(res.data.records)
+          : res.data.records;
         total.value = res.data.total;
         // 鏁版嵁鍔犺浇瀹屾垚鍚庢鏌ュ簱瀛�
         // checkStockAndCreatePurchase();
@@ -346,6 +426,9 @@
 
   // 琛ㄦ牸琛岀被鍚�
   const tableRowClassName = ({ row }) => {
+    if (row?.__isGroup) {
+      return "row-tank-group";
+    }
     const stock = Number(row?.qualifiedUnLockedQuantity ?? 0);
     const warn = Number(row?.warnNum ?? 0);
     if (!Number.isFinite(stock) || !Number.isFinite(warn)) {
@@ -379,6 +462,12 @@
 </script>
 
 <style scoped lang="scss">
+  .actions {
+    display: flex;
+    justify-content: space-between;
+    margin-bottom: 12px;
+  }
+
   :deep(.row-low-stock td) {
     background-color: #fde2e2;
     color: #c45656;
@@ -387,4 +476,34 @@
   :deep(.row-low-stock:hover > td) {
     background-color: #fcd4d4;
   }
+
+  :deep(.row-tank-group > td) {
+    background-color: #eef5ff;
+  }
+
+  :deep(.row-tank-group:hover > td) {
+    background-color: #e4eefc;
+  }
+
+  :deep(.tank-group-band) {
+    display: flex;
+    align-items: center;
+    width: 100%;
+    font-size: 13px;
+    line-height: 20px;
+  }
+
+  :deep(.tank-group-band__name) {
+    margin-right: auto;
+    padding-left: 8px;
+    border-left: 3px solid #1d6fd8;
+    font-weight: 700;
+    color: #1d6fd8;
+  }
+
+  :deep(.tank-group-band__stat) {
+    margin-left: 24px;
+    font-weight: 600;
+    color: #3a7bd5;
+  }
 </style>
diff --git a/src/views/inventoryManagement/stockManagement/index.vue b/src/views/inventoryManagement/stockManagement/index.vue
index b3aa7ee..21d9827 100644
--- a/src/views/inventoryManagement/stockManagement/index.vue
+++ b/src/views/inventoryManagement/stockManagement/index.vue
@@ -6,7 +6,7 @@
                      :label="tab.productName"
                      :name="tab.id"
                      :key="tab.id">
-          <Record :product-id="tab.id" v-if="tab.id === activeTab" />
+          <Record :product-id="tab.id" :product-name="tab.productName" v-if="tab.id === activeTab" />
         </el-tab-pane>
       </el-tabs>
     </div>
diff --git a/src/views/officeProcessAutomation/ApproveManage/approve-list/approveListConstants.js b/src/views/officeProcessAutomation/ApproveManage/approve-list/approveListConstants.js
index e2f1e45..3419f53 100644
--- a/src/views/officeProcessAutomation/ApproveManage/approve-list/approveListConstants.js
+++ b/src/views/officeProcessAutomation/ApproveManage/approve-list/approveListConstants.js
@@ -460,6 +460,7 @@
     purchaseContractNumber: row.purchaseContractNumber || "",
     quotationNo: row.quotationNo || "",
     shippingNo: row.shippingNo || "",
+    salesContractNo: row.salesContractNo || "",
   };
 }
 
diff --git a/src/views/officeProcessAutomation/ApproveManage/approve-list/components/ApproveDetailPanel.vue b/src/views/officeProcessAutomation/ApproveManage/approve-list/components/ApproveDetailPanel.vue
index d057f16..807c458 100644
--- a/src/views/officeProcessAutomation/ApproveManage/approve-list/components/ApproveDetailPanel.vue
+++ b/src/views/officeProcessAutomation/ApproveManage/approve-list/components/ApproveDetailPanel.vue
@@ -145,6 +145,53 @@
           </div>
         </div>
       </template>
+
+      <!-- 閿�鍞彴璐﹀鎵硅鎯咃紙鍗栨补 / 浠e偍锛� -->
+      <template v-else-if="row.businessType === 19">
+        <div v-if="detailData && Object.keys(detailData).length" class="sales-ledger-detail">
+          <el-divider content-position="left">閿�鍞彴璐﹁鎯�</el-divider>
+          <el-descriptions :column="2" border>
+            <el-descriptions-item label="閿�鍞悎鍚屽彿">{{ detailData.salesContractNo || "--" }}</el-descriptions-item>
+            <el-descriptions-item label="閿�鍞被鍨�">{{ detailData.ledgerType || "--" }}</el-descriptions-item>
+            <el-descriptions-item label="瀹㈡埛鍚嶇О">{{ detailData.customerName || "--" }}</el-descriptions-item>
+            <el-descriptions-item label="涓氬姟鍛�">{{ detailData.salesman || "--" }}</el-descriptions-item>
+            <el-descriptions-item label="椤圭洰鍚嶇О">{{ detailData.projectName || "--" }}</el-descriptions-item>
+            <el-descriptions-item label="浠樻鏂瑰紡">{{ detailData.paymentMethod || "--" }}</el-descriptions-item>
+            <el-descriptions-item v-if="detailData.ledgerType === '浠e偍'"
+                                  label="娌瑰簱">{{ detailData.oilDepotName || "--" }}</el-descriptions-item>
+            <el-descriptions-item v-if="detailData.ledgerType === '浠e偍'"
+                                  label="鍌ㄧ綈鍙�">{{ detailData.tankNo || "--" }}</el-descriptions-item>
+            <el-descriptions-item label="鍚堝悓閲戦" :span="2">
+              <span style="font-size: 18px; color: #e6a23c; font-weight: bold;">
+                楼{{ Number(detailData.contractAmount ?? 0).toFixed(2) }}
+              </span>
+              <span v-if="detailData.exceedsTrustFund"
+                    class="reject-text"
+                    style="margin-left: 12px;">
+                宸茶秴鍑鸿瀹㈡埛淇℃墭鍩洪噾{{ detailData.trustFund != null ? `锛堜俊鎵樺熀閲戯細${detailData.trustFund}锛塦 : "" }}
+              </span>
+            </el-descriptions-item>
+          </el-descriptions>
+          <div v-if="detailData.productData && detailData.productData.length"
+               style="margin-top: 20px;">
+            <h4>浜у搧鏄庣粏</h4>
+            <el-table :data="detailData.productData"
+                      border
+                      style="width: 100%">
+              <el-table-column prop="productCategory" label="浜у搧澶х被" />
+              <el-table-column prop="specificationModel" label="瑙勬牸鍨嬪彿" />
+              <el-table-column prop="unit" label="鍗曚綅" />
+              <el-table-column prop="quantity" label="鏁伴噺" />
+              <el-table-column prop="taxInclusiveUnitPrice" label="鍚◣鍗曚环">
+                <template #default="scope">楼{{ Number(scope.row.taxInclusiveUnitPrice ?? 0).toFixed(2) }}</template>
+              </el-table-column>
+              <el-table-column prop="taxInclusiveTotalPrice" label="鍚◣鎬讳环">
+                <template #default="scope">楼{{ Number(scope.row.taxInclusiveTotalPrice ?? 0).toFixed(2) }}</template>
+              </el-table-column>
+            </el-table>
+          </div>
+        </div>
+      </template>
     </div>
     <div v-if="attachmentList.length"
          class="detail-block">
@@ -199,9 +246,9 @@
   const formResolved = computed(() => resolveInstanceFormFields(props.row));
 
 
-  // 鏄惁涓虹壒娈婂鎵圭被鍨嬶紙閲囪喘銆佸彂璐с�佹姤浠凤級
+  // 鏄惁涓虹壒娈婂鎵圭被鍨嬶紙閲囪喘銆佸彂璐с�佹姤浠枫�侀攢鍞彴璐︼級
   const isSpecialApprovalType = computed(() => {
-    return [5, 7, 6].includes(props.row.businessType);
+    return [5, 7, 6, 19].includes(props.row.businessType);
   });
 
   // 璇︽儏鏁版嵁锛堢洿鎺ヤ娇鐢ㄤ紶鍏ョ殑 detail-data 鍙傛暟锛�
diff --git a/src/views/officeProcessAutomation/ApproveManage/approve-list/index.vue b/src/views/officeProcessAutomation/ApproveManage/approve-list/index.vue
index 4a9cf29..853b4f7 100644
--- a/src/views/officeProcessAutomation/ApproveManage/approve-list/index.vue
+++ b/src/views/officeProcessAutomation/ApproveManage/approve-list/index.vue
@@ -63,6 +63,9 @@
         :total="page.total"
         @pagination="pagination"
       >
+        <template #bizNo="{ row }">
+          <span>{{ businessNoOf(row) || "-" }}</span>
+        </template>
         <template #approveType="{ row }">
           <span class="approve-type-cell" :style="approvalTypeStyle(row.approvalType)">
             {{ approvalTypeLabel(row.approvalType) }}
@@ -361,6 +364,7 @@
   onBusinessTypePick,
   backToBusinessTypePick,
   approvalTypeLabel,
+  businessNoOf,
   approvalActionLabel,
   searchForm,
   tableLoading,
diff --git a/src/views/officeProcessAutomation/ApproveManage/approve-list/useApproveList.js b/src/views/officeProcessAutomation/ApproveManage/approve-list/useApproveList.js
index 737e2de..b413fd8 100644
--- a/src/views/officeProcessAutomation/ApproveManage/approve-list/useApproveList.js
+++ b/src/views/officeProcessAutomation/ApproveManage/approve-list/useApproveList.js
@@ -13,6 +13,7 @@
 import { getQuotationList } from "@/api/salesManagement/salesQuotation.js";
 import { getPurchaseByCode } from "@/api/procurementManagement/procurementLedger.js";
 import { getDeliveryDetailByShippingNo } from "@/api/salesManagement/deliveryLedger.js";
+import { ledgerListPage } from "@/api/salesManagement/salesLedger.js";
 import useUserStore from "@/store/modules/user";
 import { Search } from "@element-plus/icons-vue";
 import { ElMessage, ElMessageBox } from "element-plus";
@@ -120,6 +121,18 @@
     return hit?.label || "";
   }
 
+  // 鍒楄〃銆屼笟鍔″崟鍙枫�嶏細鎸変笟鍔$被鍨嬪彇瀵瑰簲鐨勫崟鍙凤紙19=閿�鍞彴璐﹀鎵癸級
+  function businessNoOf(row) {
+    return (
+      row?.salesContractNo ||
+      row?.quotationNo ||
+      row?.purchaseContractNumber ||
+      row?.shippingNo ||
+      row?.bizId ||
+      ""
+    );
+  }
+
   function countTemplatesByBusinessType(type) {
     return allSubmitTemplates.value.filter((card) => matchBusinessTypeValue(card.businessType, type)).length;
   }
@@ -142,6 +155,13 @@
     // { label: "鐢宠浜虹紪鍙�", prop: "applicantNo", width: 110 },
     { label: "鍙戣捣浜�", prop: "applicantName", minWidth: 100 },
     { label: "妯℃澘绫诲瀷", prop: "businessName", minWidth: 120 },
+    {
+      label: "涓氬姟鍗曞彿",
+      prop: "businessNo",
+      minWidth: 170,
+      dataType: "slot",
+      slot: "bizNo",
+    },
     {
       label: "瀹℃壒绫诲瀷",
       prop: "approvalType",
@@ -326,13 +346,29 @@
         detailData.value = res?.data || res || {};
       }
     }
-    
+
+    // 閿�鍞彴璐﹀鎵癸細鐢ㄥ鎵逛簨鐢卞瓧娈垫壙杞界殑"閿�鍞悎鍚屽彿"鍘绘煡鍙拌处鍒楄〃
+    else if (row.businessType === 19) {
+      detailData.value = await fetchSalesLedgerByContractNo(row?.salesContractNo);
+    }
+
     // 鍏朵粬瀹℃壒绫诲瀷
     else {
       detailData.value = {};
     }
-    
+
     detailDialog.visible = true;
+  }
+
+  async function fetchSalesLedgerByContractNo(salesContractNo) {
+    if (!salesContractNo) return {};
+    // /sales/ledger/listPage 鐩存帴杩斿洖 IPage锛堥《灞� records锛夛紝娌℃湁 code/msg 澶栧眰
+    const res = await ledgerListPage({
+      salesContractNo,
+      pageNum: 1,
+      pageSize: 1,
+    });
+    return res?.records?.[0] || {};
   }
 
   async function openApprove(row) {
@@ -373,6 +409,11 @@
         const res = await getDeliveryDetailByShippingNo({ shippingNo });
         detailData.value = res?.data || res || {};
       }
+    }
+
+    // 閿�鍞彴璐﹀鎵癸細鐢ㄥ鎵逛簨鐢卞瓧娈垫壙杞界殑"閿�鍞悎鍚屽彿"鍘绘煡鍙拌处鍒楄〃
+    else if (row.businessType === 19) {
+      detailData.value = await fetchSalesLedgerByContractNo(row?.salesContractNo);
     }
 
     // 鍏朵粬瀹℃壒绫诲瀷
@@ -686,6 +727,7 @@
     selectedBusinessType,
     selectedBusinessTypeLabel,
     businessTypeLabel,
+    businessNoOf,
     countTemplatesByBusinessType,
     submitTemplatesLoading,
     handleQuery,
diff --git a/src/views/outsourcingManagement/order/index.vue b/src/views/outsourcingManagement/order/index.vue
new file mode 100644
index 0000000..1c68210
--- /dev/null
+++ b/src/views/outsourcingManagement/order/index.vue
@@ -0,0 +1,952 @@
+<template>
+  <div class="app-container">
+    <div class="search_form">
+      <el-form :model="searchForm"
+               :inline="true">
+        <el-form-item label="濮斿璁㈠崟鍙凤細">
+          <el-input v-model="searchForm.orderNo"
+                    placeholder="璇疯緭鍏�"
+                    clearable
+                    prefix-icon="Search"
+                    style="width: 180px"
+                    @change="handleQuery" />
+        </el-form-item>
+        <el-form-item label="鍚堜綔鍟嗭細">
+          <el-select v-model="searchForm.partnerId"
+                     placeholder="璇烽�夋嫨"
+                     clearable
+                     filterable
+                     style="width: 200px"
+                     @change="handleQuery">
+            <el-option v-for="item in partnerOptions"
+                       :key="item.id"
+                       :label="item.partnerName"
+                       :value="item.id" />
+          </el-select>
+        </el-form-item>
+        <el-form-item label="椤圭洰鍚嶇О锛�">
+          <el-input v-model="searchForm.projectName"
+                    placeholder="璇疯緭鍏�"
+                    clearable
+                    style="width: 160px"
+                    @change="handleQuery" />
+        </el-form-item>
+        <el-form-item label="鐘舵�侊細">
+          <el-select v-model="searchForm.status"
+                     placeholder="璇烽�夋嫨"
+                     clearable
+                     style="width: 140px"
+                     @change="handleQuery">
+            <el-option v-for="item in statusOptions"
+                       :key="item.value"
+                       :label="item.label"
+                       :value="item.value" />
+          </el-select>
+        </el-form-item>
+        <el-form-item label="鐢宠鏃ユ湡锛�">
+          <el-date-picker v-model="dateRange"
+                          type="daterange"
+                          value-format="YYYY-MM-DD"
+                          format="YYYY-MM-DD"
+                          range-separator="鑷�"
+                          start-placeholder="寮�濮嬫棩鏈�"
+                          end-placeholder="缁撴潫鏃ユ湡"
+                          @change="handleQuery" />
+        </el-form-item>
+        <el-form-item>
+          <el-button type="primary"
+                     @click="handleQuery">鎼滅储</el-button>
+          <el-button @click="resetSearch">閲嶇疆</el-button>
+        </el-form-item>
+      </el-form>
+    </div>
+    <div class="table_list">
+      <div class="actions">
+        <div></div>
+        <div>
+          <el-button type="primary"
+                     @click="openForm('add')">鏂板濮斿璁㈠崟</el-button>
+          <el-button @click="handleExport">瀵煎嚭</el-button>
+          <el-button type="danger"
+                     plain
+                     @click="handleBatchDelete">鍒犻櫎</el-button>
+        </div>
+      </div>
+      <el-table :data="tableData"
+                border
+                v-loading="tableLoading"
+                @selection-change="handleSelectionChange"
+                style="width: 100%"
+                height="calc(100vh - 21.5em)">
+        <el-table-column align="center"
+                         type="selection"
+                         :selectable="isDraft"
+                         width="55" />
+        <el-table-column align="center"
+                         label="搴忓彿"
+                         type="index"
+                         width="60" />
+        <el-table-column label="濮斿璁㈠崟鍙�"
+                         prop="orderNo"
+                         min-width="160"
+                         show-overflow-tooltip />
+        <el-table-column label="鍚堜綔鍟�"
+                         prop="partnerName"
+                         min-width="180"
+                         show-overflow-tooltip />
+        <el-table-column label="椤圭洰鍚嶇О"
+                         prop="projectName"
+                         min-width="140"
+                         show-overflow-tooltip />
+        <el-table-column label="鐢宠鏃ユ湡"
+                         prop="applyDate"
+                         min-width="110"
+                         show-overflow-tooltip />
+        <el-table-column label="棰勮浜や粯鏃ユ湡"
+                         prop="expectedDeliveryDate"
+                         min-width="120"
+                         show-overflow-tooltip />
+        <el-table-column label="鍚堝悓閲戦(鍏�)"
+                         prop="contractAmount"
+                         min-width="120"
+                         align="right">
+          <template #default="scope">
+            {{ formatAmount(scope.row.contractAmount) }}
+          </template>
+        </el-table-column>
+        <el-table-column label="浠樻鏂瑰紡"
+                         prop="paymentMethod"
+                         min-width="100"
+                         show-overflow-tooltip />
+        <el-table-column label="鐘舵��"
+                         prop="status"
+                         align="center"
+                         width="100">
+          <template #default="scope">
+            <el-tag :type="statusTagType(scope.row.status)"
+                    size="small">
+              {{ statusLabel(scope.row.status) }}
+            </el-tag>
+          </template>
+        </el-table-column>
+        <el-table-column label="纭鏃堕棿"
+                         prop="confirmTime"
+                         min-width="160"
+                         show-overflow-tooltip />
+        <el-table-column label="浣滃簾鍘熷洜"
+                         prop="cancelReason"
+                         min-width="140"
+                         show-overflow-tooltip />
+        <el-table-column label="鍒涘缓鏃堕棿"
+                         prop="createTime"
+                         min-width="160"
+                         show-overflow-tooltip />
+        <el-table-column fixed="right"
+                         label="鎿嶄綔"
+                         width="220"
+                         align="center">
+          <template #default="scope">
+            <el-button link
+                       type="primary"
+                       @click="openForm('view', scope.row)">璇︽儏</el-button>
+            <el-button v-if="scope.row.status === 0"
+                       link
+                       type="primary"
+                       @click="openForm('edit', scope.row)">缂栬緫</el-button>
+            <el-button v-if="scope.row.status === 0"
+                       link
+                       type="primary"
+                       @click="handleSubmitOrder(scope.row)">鎻愪氦</el-button>
+            <el-button v-if="scope.row.status === 1"
+                       link
+                       type="primary"
+                       @click="handleCompleteOrder(scope.row)">瀹屾垚</el-button>
+            <el-button v-if="scope.row.status === 0 || scope.row.status === 1"
+                       link
+                       type="danger"
+                       @click="handleCancelOrder(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="dialogTitle"
+               width="90%"
+               top="5vh"
+               :close-on-click-modal="false"
+               @close="closeDia">
+      <el-form :model="form"
+               label-width="130px"
+               label-position="top"
+               :rules="rules"
+               ref="formRef"
+               :disabled="isView">
+        <el-row :gutter="30">
+          <el-col :span="8">
+            <el-form-item label="鍚堜綔鍟嗭細"
+                          prop="partnerId">
+              <el-select v-model="form.partnerId"
+                         placeholder="璇烽�夋嫨"
+                         clearable
+                         filterable
+                         style="width: 100%">
+                <el-option v-for="item in partnerOptions"
+                           :key="item.id"
+                           :label="item.partnerName"
+                           :value="item.id" />
+              </el-select>
+            </el-form-item>
+          </el-col>
+          <el-col :span="8">
+            <el-form-item label="椤圭洰鍚嶇О锛�"
+                          prop="projectName">
+              <el-input v-model="form.projectName"
+                        placeholder="璇疯緭鍏�"
+                        clearable />
+            </el-form-item>
+          </el-col>
+          <el-col :span="8">
+            <el-form-item label="浠樻鏂瑰紡锛�"
+                          prop="paymentMethod">
+              <el-input v-model="form.paymentMethod"
+                        placeholder="璇疯緭鍏�"
+                        clearable />
+            </el-form-item>
+          </el-col>
+        </el-row>
+        <el-row :gutter="30">
+          <el-col :span="8">
+            <el-form-item label="鐢宠鏃ユ湡锛�"
+                          prop="applyDate">
+              <el-date-picker v-model="form.applyDate"
+                              type="date"
+                              value-format="YYYY-MM-DD"
+                              format="YYYY-MM-DD"
+                              placeholder="璇烽�夋嫨"
+                              style="width: 100%" />
+            </el-form-item>
+          </el-col>
+          <el-col :span="8">
+            <el-form-item label="棰勮浜や粯鏃ユ湡锛�"
+                          prop="expectedDeliveryDate">
+              <el-date-picker v-model="form.expectedDeliveryDate"
+                              type="date"
+                              value-format="YYYY-MM-DD"
+                              format="YYYY-MM-DD"
+                              placeholder="璇烽�夋嫨"
+                              style="width: 100%" />
+            </el-form-item>
+          </el-col>
+          <el-col :span="8">
+            <el-form-item label="鍚堝悓閲戦(鍏�)">
+              <el-input :model-value="formatAmount(totalAmount)"
+                        readonly />
+            </el-form-item>
+          </el-col>
+        </el-row>
+        <el-row :gutter="30">
+          <el-col :span="24">
+            <el-form-item label="澶囨敞锛�"
+                          prop="remarks">
+              <el-input v-model="form.remarks"
+                        type="textarea"
+                        :rows="2"
+                        placeholder="璇疯緭鍏�"
+                        clearable />
+            </el-form-item>
+          </el-col>
+        </el-row>
+      </el-form>
+      <div class="detail-header">
+        <span class="detail-title">浜у搧鏄庣粏</span>
+        <el-button v-if="!isView"
+                   type="primary"
+                   size="small"
+                   @click="openScrapSelect">閫夋姤搴熷搧</el-button>
+        <el-button v-if="!isView"
+                   size="small"
+                   @click="addEmptyDetail">鏂板琛�</el-button>
+      </div>
+      <el-table :data="form.productData"
+                border
+                size="small"
+                style="width: 100%">
+        <el-table-column align="center"
+                         label="搴忓彿"
+                         type="index"
+                         width="55" />
+        <el-table-column label="浜у搧澶х被"
+                         prop="productCategory"
+                         min-width="120"
+                         show-overflow-tooltip />
+        <el-table-column label="瑙勬牸鍨嬪彿"
+                         prop="specificationModel"
+                         min-width="110"
+                         show-overflow-tooltip />
+        <el-table-column label="鍗曚綅"
+                         prop="unit"
+                         min-width="70" />
+        <el-table-column label="鏁伴噺"
+                         prop="quantity"
+                         min-width="110">
+          <template #default="scope">
+            <el-input-number v-if="!isView"
+                             v-model="scope.row.quantity"
+                             :min="0"
+                             :precision="4"
+                             :step="1"
+                             style="width: 100%" />
+            <span v-else>{{ scope.row.quantity }}</span>
+          </template>
+        </el-table-column>
+        <el-table-column label="绋庣巼(%)"
+                         prop="taxRate"
+                         min-width="110">
+          <template #default="scope">
+            <el-input-number v-if="!isView"
+                             v-model="scope.row.taxRate"
+                             :min="0"
+                             :max="100"
+                             :precision="2"
+                             :step="1"
+                             style="width: 100%" />
+            <span v-else>{{ scope.row.taxRate }}</span>
+          </template>
+        </el-table-column>
+        <el-table-column label="鍚◣鍗曚环(鍏�)"
+                         prop="taxInclusiveUnitPrice"
+                         min-width="130">
+          <template #default="scope">
+            <el-input-number v-if="!isView"
+                             v-model="scope.row.taxInclusiveUnitPrice"
+                             :min="0"
+                             :precision="2"
+                             :step="0.01"
+                             style="width: 100%" />
+            <span v-else>{{ scope.row.taxInclusiveUnitPrice }}</span>
+          </template>
+        </el-table-column>
+        <el-table-column label="鍚◣鎬讳环(鍏�)"
+                         prop="taxInclusiveTotalPrice"
+                         min-width="120"
+                         align="right">
+          <template #default="scope">
+            {{ formatAmount(lineTotal(scope.row)) }}
+          </template>
+        </el-table-column>
+        <el-table-column label="鎶ュ簾鍝�"
+                         prop="isScrap"
+                         align="center"
+                         width="80">
+          <template #default="scope">
+            <el-tag :type="scope.row.isScrap ? 'warning' : 'info'"
+                    size="small">
+              {{ scope.row.isScrap ? "鏄�" : "鍚�" }}
+            </el-tag>
+          </template>
+        </el-table-column>
+        <el-table-column label="鎵瑰彿"
+                         prop="batchNo"
+                         min-width="130"
+                         show-overflow-tooltip />
+        <el-table-column label="鍙敤閲�"
+                         prop="availableQuantity"
+                         min-width="100"
+                         align="right" />
+        <el-table-column label="澶囨敞"
+                         prop="remark"
+                         min-width="130">
+          <template #default="scope">
+            <el-input v-if="!isView"
+                      v-model="scope.row.remark"
+                      placeholder="璇疯緭鍏�"
+                      clearable />
+            <span v-else>{{ scope.row.remark }}</span>
+          </template>
+        </el-table-column>
+        <el-table-column v-if="!isView"
+                         fixed="right"
+                         label="鎿嶄綔"
+                         width="70"
+                         align="center">
+          <template #default="scope">
+            <el-button link
+                       type="danger"
+                       @click="removeDetail(scope.$index)">鍒犻櫎</el-button>
+          </template>
+        </el-table-column>
+      </el-table>
+      <template #footer>
+        <div class="dialog-footer">
+          <el-button v-if="!isView"
+                     type="primary"
+                     @click="submitForm">纭</el-button>
+          <el-button @click="closeDia">{{ isView ? "鍏抽棴" : "鍙栨秷" }}</el-button>
+        </div>
+      </template>
+    </el-dialog>
+    <!-- 鎶ュ簾鍝侀�夋枡锛堝彧璇伙紝涓嶆墸搴撳瓨銆佷笉鍗犵敤锛� -->
+    <el-dialog v-model="scrapDialogVisible"
+               title="閫夋嫨鎶ュ簾鍝�"
+               width="70%"
+               append-to-body>
+      <el-form :model="scrapSearch"
+               :inline="true">
+        <el-form-item label="浜у搧鍚嶇О锛�">
+          <el-input v-model="scrapSearch.productName"
+                    placeholder="璇疯緭鍏�"
+                    clearable
+                    style="width: 160px" />
+        </el-form-item>
+        <el-form-item label="鎵瑰彿锛�">
+          <el-input v-model="scrapSearch.batchNo"
+                    placeholder="璇疯緭鍏�"
+                    clearable
+                    style="width: 160px" />
+        </el-form-item>
+        <el-form-item>
+          <el-button type="primary"
+                     @click="handleScrapQuery">鎼滅储</el-button>
+        </el-form-item>
+      </el-form>
+      <el-table :data="scrapTableData"
+                border
+                v-loading="scrapLoading"
+                highlight-current-row
+                style="width: 100%"
+                height="360px"
+                @current-change="handleScrapCurrentChange">
+        <el-table-column align="center"
+                         label="搴忓彿"
+                         type="index"
+                         width="60" />
+        <el-table-column label="浜у搧鍚嶇О"
+                         prop="productName"
+                         min-width="140"
+                         show-overflow-tooltip />
+        <el-table-column label="瑙勬牸鍨嬪彿"
+                         prop="model"
+                         min-width="120"
+                         show-overflow-tooltip />
+        <el-table-column label="鎵瑰彿"
+                         prop="batchNo"
+                         min-width="140"
+                         show-overflow-tooltip />
+        <el-table-column label="鍗曚綅"
+                         prop="unit"
+                         min-width="70" />
+        <el-table-column label="搴撳瓨鏁伴噺"
+                         prop="qualitity"
+                         min-width="100"
+                         align="right" />
+        <el-table-column label="閿佸畾鏁伴噺"
+                         prop="lockedQuantity"
+                         min-width="100"
+                         align="right" />
+        <el-table-column label="鍙敤鏁伴噺"
+                         prop="unLockedQuantity"
+                         min-width="100"
+                         align="right" />
+        <el-table-column label="澶囨敞"
+                         prop="remark"
+                         min-width="120"
+                         show-overflow-tooltip />
+      </el-table>
+      <pagination v-show="scrapTotal > 0"
+                  :total="scrapTotal"
+                  layout="total, sizes, prev, pager, next, jumper"
+                  :page="scrapPage.current"
+                  :limit="scrapPage.size"
+                  @pagination="scrapPaginationChange" />
+      <template #footer>
+        <div class="dialog-footer">
+          <el-button type="primary"
+                     @click="confirmScrapSelect">纭</el-button>
+          <el-button @click="scrapDialogVisible = false">鍙栨秷</el-button>
+        </div>
+      </template>
+    </el-dialog>
+  </div>
+</template>
+
+<script setup>
+  import { ref, reactive, computed, toRefs, getCurrentInstance, onMounted } from "vue";
+  import pagination from "@/components/PIMTable/Pagination.vue";
+  import { ElMessageBox } from "element-plus";
+  import {
+    listOutsourcingOrder,
+    getOutsourcingOrder,
+    addOutsourcingOrder,
+    editOutsourcingOrder,
+    delOutsourcingOrder,
+    submitOutsourcingOrder,
+    completeOutsourcingOrder,
+    cancelOutsourcingOrder,
+    exportOutsourcingOrder,
+    scrapStockPage,
+  } from "@/api/outsourcing/order.js";
+  import { getPartnerOptions } from "@/api/outsourcing/partner.js";
+
+  const { proxy } = getCurrentInstance();
+  const tableData = ref([]);
+  const selectedRows = ref([]);
+  const tableLoading = ref(false);
+  const dialogFormVisible = ref(false);
+  const operationType = ref("");
+  const partnerOptions = ref([]);
+  const dateRange = ref([]);
+  const page = reactive({
+    current: 1,
+    size: 10,
+  });
+  const total = ref(0);
+
+  const statusOptions = [
+    { label: "鑽夌", value: 0 },
+    { label: "宸茬‘璁�", value: 1 },
+    { label: "宸插畬鎴�", value: 2 },
+    { label: "宸蹭綔搴�", value: 3 },
+  ];
+
+  const statusLabelMap = {
+    0: "鑽夌",
+    1: "宸茬‘璁�",
+    2: "宸插畬鎴�",
+    3: "宸蹭綔搴�",
+  };
+
+  const statusTagMap = {
+    0: "info",
+    1: "primary",
+    2: "success",
+    3: "danger",
+  };
+
+  const statusLabel = status => statusLabelMap[status] ?? status;
+  const statusTagType = status => statusTagMap[status] || "info";
+
+  const data = reactive({
+    searchForm: {
+      orderNo: "",
+      partnerId: "",
+      projectName: "",
+      status: "",
+    },
+    form: {},
+    rules: {
+      partnerId: [{ required: true, message: "璇烽�夋嫨鍚堜綔鍟�", trigger: "change" }],
+      projectName: [{ required: true, message: "璇疯緭鍏ラ」鐩悕绉�", trigger: "blur" }],
+      applyDate: [{ required: true, message: "璇烽�夋嫨鐢宠鏃ユ湡", trigger: "change" }],
+    },
+  });
+  const { searchForm, form, rules } = toRefs(data);
+
+  const isView = computed(() => operationType.value === "view");
+  const isDraft = row => row.status === 0;
+  const dialogTitle = computed(() => {
+    if (operationType.value === "add") {
+      return "鏂板濮斿璁㈠崟";
+    }
+    return operationType.value === "edit" ? "缂栬緫濮斿璁㈠崟" : "濮斿璁㈠崟璇︽儏";
+  });
+
+  const buildEmptyForm = () => ({
+    id: null,
+    partnerId: undefined,
+    projectName: "",
+    applyDate: today(),
+    expectedDeliveryDate: "",
+    paymentMethod: "",
+    remarks: "",
+    productData: [],
+  });
+
+  function today() {
+    const d = new Date();
+    const month = String(d.getMonth() + 1).padStart(2, "0");
+    const day = String(d.getDate()).padStart(2, "0");
+    return `${d.getFullYear()}-${month}-${day}`;
+  }
+
+  const formatAmount = value => {
+    const num = Number(value);
+    return Number.isFinite(num) ? num.toFixed(2) : "0.00";
+  };
+
+  // 鍚◣鎬讳环鐢辨暟閲� 脳 鍚◣鍗曚环寰楀嚭锛屽悗绔細鎸夋槑缁嗗悎璁¤鐩� contractAmount
+  const lineTotal = row => {
+    const quantity = Number(row?.quantity) || 0;
+    const price = Number(row?.taxInclusiveUnitPrice) || 0;
+    return Math.round(quantity * price * 100) / 100;
+  };
+
+  const totalAmount = computed(() =>
+    (form.value.productData || []).reduce((sum, row) => sum + lineTotal(row), 0)
+  );
+
+  // 鍘绘帀绌哄�硷紝閬垮厤 status='' 杩欑被绌轰覆琚悗绔綋鎴� 0锛堣崏绋匡級瑙f瀽
+  const compact = obj =>
+    Object.fromEntries(
+      Object.entries(obj).filter(([, v]) => v !== "" && v !== null && v !== undefined)
+    );
+
+  const getList = () => {
+    tableLoading.value = true;
+    const [startDate, endDate] = dateRange.value || [];
+    listOutsourcingOrder({
+      pageNum: page.current,
+      pageSize: page.size,
+      ...compact(searchForm.value),
+      startDate,
+      endDate,
+    })
+      .then(res => {
+        tableLoading.value = false;
+        // 濮斿璁㈠崟鍒楄〃杩斿洖鐨勬槸 RuoYi 缁撴瀯锛岃鍦ㄩ《灞� rows
+        tableData.value = res.rows || [];
+        total.value = res.total || 0;
+      })
+      .catch(() => {
+        tableLoading.value = false;
+      });
+  };
+
+  const handleQuery = () => {
+    page.current = 1;
+    getList();
+  };
+
+  const resetSearch = () => {
+    searchForm.value = { orderNo: "", partnerId: "", projectName: "", status: "" };
+    dateRange.value = [];
+    handleQuery();
+  };
+
+  const paginationChange = obj => {
+    page.current = obj.page;
+    page.size = obj.limit;
+    getList();
+  };
+
+  const handleSelectionChange = selection => {
+    selectedRows.value = selection;
+  };
+
+  const openForm = (type, row) => {
+    operationType.value = type;
+    form.value = buildEmptyForm();
+    proxy.resetForm("formRef");
+    dialogFormVisible.value = true;
+    if (type !== "add" && row) {
+      getOutsourcingOrder(row.id).then(res => {
+        const detail = res.data || {};
+        form.value = {
+          ...buildEmptyForm(),
+          ...detail,
+          productData: (detail.productData || []).map(item => ({ ...item })),
+        };
+      });
+    }
+  };
+
+  const addEmptyDetail = () => {
+    form.value.productData.push({
+      productId: undefined,
+      productModelId: undefined,
+      productCategory: "",
+      specificationModel: "",
+      unit: "",
+      quantity: undefined,
+      taxRate: undefined,
+      taxInclusiveUnitPrice: undefined,
+      taxInclusiveTotalPrice: undefined,
+      isScrap: false,
+      stockInventoryId: undefined,
+      batchNo: "",
+      availableQuantity: undefined,
+      remark: "",
+    });
+  };
+
+  const removeDetail = index => {
+    form.value.productData.splice(index, 1);
+  };
+
+  const submitForm = () => {
+    proxy.$refs["formRef"].validate(valid => {
+      if (!valid) {
+        return;
+      }
+      if (!form.value.productData.length) {
+        proxy.$modal.msgWarning("璇疯嚦灏戞坊鍔犱竴鏉′骇鍝佹槑缁�");
+        return;
+      }
+      // 鍙彁浜ゆ枃妗g害瀹氱殑瀛楁锛氬崟鍙�/鐘舵��/纭鏃堕棿/鍚堝悓閲戦/鍚堜綔鍟嗗悕绉扮瓑鐢卞悗绔淮鎶�
+      const payload = {
+        partnerId: form.value.partnerId,
+        projectName: form.value.projectName,
+        applyDate: form.value.applyDate,
+        expectedDeliveryDate: form.value.expectedDeliveryDate,
+        paymentMethod: form.value.paymentMethod,
+        remarks: form.value.remarks,
+        productData: form.value.productData.map(row => ({
+          productId: row.productId,
+          productModelId: row.productModelId,
+          productCategory: row.productCategory,
+          specificationModel: row.specificationModel,
+          unit: row.unit,
+          quantity: row.quantity,
+          taxRate: row.taxRate,
+          taxInclusiveUnitPrice: row.taxInclusiveUnitPrice,
+          taxInclusiveTotalPrice: lineTotal(row),
+          isScrap: !!row.isScrap,
+          stockInventoryId: row.stockInventoryId,
+          batchNo: row.batchNo,
+          availableQuantity: row.availableQuantity,
+          remark: row.remark,
+        })),
+        ...(form.value.id ? { id: form.value.id } : {}),
+      };
+      const api = form.value.id ? editOutsourcingOrder : addOutsourcingOrder;
+      api(payload).then(() => {
+        proxy.$modal.msgSuccess("鎿嶄綔鎴愬姛");
+        closeDia();
+        getList();
+      });
+    });
+  };
+
+  const closeDia = () => {
+    proxy.resetForm("formRef");
+    dialogFormVisible.value = false;
+  };
+
+  const handleSubmitOrder = row => {
+    ElMessageBox.confirm(
+      `鏄惁纭鎻愪氦璁㈠崟 ${row.orderNo}锛熸彁浜ゅ悗灏嗗崰鐢ㄦ墍閫夋姤搴熷搧鎵规鐨勫彲鐢ㄩ噺锛岄渶鍒板嚭搴撶鐞嗗鎵归�氳繃鍚庢墠鑳藉畬鎴愯鍗曘�俙,
+      "鎻愪氦",
+      {
+        confirmButtonText: "纭",
+        cancelButtonText: "鍙栨秷",
+        type: "warning",
+      }
+    )
+      .then(() => {
+        submitOutsourcingOrder(row.id).then(() => {
+          proxy.$modal.msgSuccess("鎻愪氦鎴愬姛");
+          getList();
+        });
+      })
+      .catch(() => {
+        proxy.$modal.msg("宸插彇娑�");
+      });
+  };
+
+  const handleCompleteOrder = row => {
+    ElMessageBox.confirm(`鏄惁纭瀹屾垚璁㈠崟 ${row.orderNo}锛焋, "瀹屾垚", {
+      confirmButtonText: "纭",
+      cancelButtonText: "鍙栨秷",
+      type: "warning",
+    })
+      .then(() => {
+        completeOutsourcingOrder(row.id).then(() => {
+          proxy.$modal.msgSuccess("鎿嶄綔鎴愬姛");
+          getList();
+        });
+      })
+      .catch(() => {
+        proxy.$modal.msg("宸插彇娑�");
+      });
+  };
+
+  const handleCancelOrder = row => {
+    ElMessageBox.prompt("璇疯緭鍏ヤ綔搴熷師鍥狅紙鍙笉濉級", `浣滃簾璁㈠崟 ${row.orderNo}`, {
+      confirmButtonText: "纭浣滃簾",
+      cancelButtonText: "鍙栨秷",
+      inputPlaceholder: "浣滃簾鍘熷洜",
+    })
+      .then(({ value }) => {
+        cancelOutsourcingOrder(row.id, value || "").then(() => {
+          proxy.$modal.msgSuccess("浣滃簾鎴愬姛");
+          getList();
+        });
+      })
+      .catch(() => {
+        proxy.$modal.msg("宸插彇娑�");
+      });
+  };
+
+  const handleBatchDelete = () => {
+    if (selectedRows.value.length === 0) {
+      proxy.$modal.msgWarning("璇烽�夋嫨鏁版嵁");
+      return;
+    }
+    const ids = selectedRows.value.map(item => item.id);
+    ElMessageBox.confirm("閫変腑鐨勫唴瀹瑰皢琚垹闄わ紝鏄惁纭鍒犻櫎锛熶粎鑽夌鐘舵�佸厑璁稿垹闄ゃ��", "鍒犻櫎", {
+      confirmButtonText: "纭",
+      cancelButtonText: "鍙栨秷",
+      type: "warning",
+    })
+      .then(() => {
+        delOutsourcingOrder(ids).then(() => {
+          proxy.$modal.msgSuccess("鍒犻櫎鎴愬姛");
+          getList();
+        });
+      })
+      .catch(() => {
+        proxy.$modal.msg("宸插彇娑�");
+      });
+  };
+
+  const saveExcelBlob = (blobData, filename) => {
+    const blob = new Blob([blobData], {
+      type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
+    });
+    const url = window.URL.createObjectURL(blob);
+    const link = document.createElement("a");
+    link.href = url;
+    link.download = filename;
+    document.body.appendChild(link);
+    link.click();
+    setTimeout(() => {
+      document.body.removeChild(link);
+      window.URL.revokeObjectURL(url);
+    }, 100);
+  };
+
+  const handleExport = () => {
+    ElMessageBox.confirm("鏄惁纭瀵煎嚭锛�", "瀵煎嚭", {
+      confirmButtonText: "纭",
+      cancelButtonText: "鍙栨秷",
+      type: "warning",
+    })
+      .then(() => {
+        const [startDate, endDate] = dateRange.value || [];
+        exportOutsourcingOrder({
+          ...compact(searchForm.value),
+          startDate,
+          endDate,
+        }).then(res => {
+          saveExcelBlob(res, "濮斿璁㈠崟.xlsx");
+        });
+      })
+      .catch(() => {
+        proxy.$modal.msg("宸插彇娑�");
+      });
+  };
+
+  // 鎶ュ簾鍝侀�夋枡锛氬彧璇诲甫鍑猴紝涓嶆墸搴撳瓨銆佷笉鍗犵敤
+  const scrapDialogVisible = ref(false);
+  const scrapLoading = ref(false);
+  const scrapTableData = ref([]);
+  const scrapSelectedRow = ref(null);
+  const scrapTotal = ref(0);
+  const scrapPage = reactive({ current: 1, size: 10 });
+  const scrapSearch = reactive({ productName: "", batchNo: "" });
+
+  const getScrapList = () => {
+    scrapLoading.value = true;
+    scrapStockPage({
+      pageNum: scrapPage.current,
+      pageSize: scrapPage.size,
+      productName: scrapSearch.productName || undefined,
+      batchNo: scrapSearch.batchNo || undefined,
+    })
+      .then(res => {
+        scrapLoading.value = false;
+        scrapTableData.value = res.data?.records || [];
+        scrapTotal.value = res.data?.total || 0;
+      })
+      .catch(() => {
+        scrapLoading.value = false;
+      });
+  };
+
+  const openScrapSelect = () => {
+    scrapSelectedRow.value = null;
+    scrapSearch.productName = "";
+    scrapSearch.batchNo = "";
+    scrapPage.current = 1;
+    scrapDialogVisible.value = true;
+    getScrapList();
+  };
+
+  const handleScrapQuery = () => {
+    scrapPage.current = 1;
+    getScrapList();
+  };
+
+  const scrapPaginationChange = obj => {
+    scrapPage.current = obj.page;
+    scrapPage.size = obj.limit;
+    getScrapList();
+  };
+
+  const handleScrapCurrentChange = row => {
+    scrapSelectedRow.value = row;
+  };
+
+  const confirmScrapSelect = () => {
+    const row = scrapSelectedRow.value;
+    if (!row) {
+      proxy.$modal.msgWarning("璇烽�夋嫨涓�鏉℃姤搴熷搧鎵规");
+      return;
+    }
+    form.value.productData.push({
+      productId: row.productId,
+      productModelId: row.productModelId,
+      productCategory: row.productName || "",
+      specificationModel: row.model || "",
+      unit: row.unit || "",
+      quantity: undefined,
+      taxRate: undefined,
+      taxInclusiveUnitPrice: undefined,
+      taxInclusiveTotalPrice: undefined,
+      isScrap: true,
+      stockInventoryId: row.id,
+      batchNo: row.batchNo || "",
+      availableQuantity: row.unLockedQuantity,
+      remark: "",
+    });
+    scrapDialogVisible.value = false;
+  };
+
+  onMounted(() => {
+    getList();
+    getPartnerOptions().then(res => {
+      partnerOptions.value = res.data || [];
+    });
+  });
+</script>
+
+<style scoped lang="scss">
+  .search_form {
+    margin-bottom: 16px;
+  }
+
+  .actions {
+    display: flex;
+    justify-content: flex-end;
+    margin-bottom: 12px;
+  }
+
+  .detail-header {
+    display: flex;
+    align-items: center;
+    gap: 12px;
+    margin: 8px 0 12px;
+
+    .detail-title {
+      flex: 1;
+      font-size: 15px;
+      font-weight: 600;
+      color: #1d6fd8;
+    }
+  }
+</style>
diff --git a/src/views/outsourcingManagement/partner/index.vue b/src/views/outsourcingManagement/partner/index.vue
new file mode 100644
index 0000000..5ba20b0
--- /dev/null
+++ b/src/views/outsourcingManagement/partner/index.vue
@@ -0,0 +1,668 @@
+<template>
+  <div class="app-container">
+    <div class="search_form">
+      <el-form :model="searchForm"
+               :inline="true">
+        <el-form-item label="鍚堜綔鍟嗗悕绉帮細">
+          <el-input v-model="searchForm.partnerName"
+                    placeholder="璇疯緭鍏�"
+                    clearable
+                    prefix-icon="Search"
+                    @change="handleQuery" />
+        </el-form-item>
+        <el-form-item label="鍚堜綔鍟嗙被鍨嬶細">
+          <el-input v-model="searchForm.partnerType"
+                    placeholder="璇疯緭鍏�"
+                    clearable
+                    @change="handleQuery" />
+        </el-form-item>
+        <el-form-item label="鏄惁鐧藉悕鍗曪細">
+          <el-select v-model="searchForm.isWhite"
+                     placeholder="璇烽�夋嫨"
+                     clearable
+                     style="width: 140px"
+                     @change="handleQuery">
+            <el-option label="鏄�"
+                       :value="1" />
+            <el-option label="鍚�"
+                       :value="0" />
+          </el-select>
+        </el-form-item>
+        <el-form-item>
+          <el-button type="primary"
+                     @click="handleQuery">鎼滅储</el-button>
+        </el-form-item>
+      </el-form>
+    </div>
+    <div class="table_list">
+      <div class="actions">
+        <div></div>
+        <div>
+          <el-button type="primary"
+                     @click="openForm('add')">鏂板鍚堜綔鍟�</el-button>
+          <el-button @click="handleExport">瀵煎嚭</el-button>
+          <el-button type="info"
+                     plain
+                     icon="Upload"
+                     @click="handleImport">瀵煎叆</el-button>
+          <el-button type="danger"
+                     plain
+                     @click="handleDelete">鍒犻櫎</el-button>
+        </div>
+      </div>
+      <el-table :data="tableData"
+                border
+                v-loading="tableLoading"
+                @selection-change="handleSelectionChange"
+                style="width: 100%"
+                height="calc(100vh - 19em)">
+        <el-table-column align="center"
+                         type="selection"
+                         width="55" />
+        <el-table-column align="center"
+                         label="搴忓彿"
+                         type="index"
+                         width="60" />
+        <el-table-column label="鍚堜綔鍟嗗悕绉�"
+                         prop="partnerName"
+                         min-width="200"
+                         show-overflow-tooltip />
+        <el-table-column label="鍚堜綔鍟嗙被鍨�"
+                         prop="partnerType"
+                         min-width="110"
+                         show-overflow-tooltip />
+        <el-table-column label="绾崇◣浜鸿瘑鍒彿"
+                         prop="taxpayerIdentificationNum"
+                         min-width="190"
+                         show-overflow-tooltip />
+        <el-table-column label="鍏徃鍦板潃"
+                         prop="companyAddress"
+                         min-width="180"
+                         show-overflow-tooltip />
+        <el-table-column label="鍏徃鐢佃瘽"
+                         prop="companyPhone"
+                         min-width="130"
+                         show-overflow-tooltip />
+        <el-table-column label="寮�鎴疯"
+                         prop="bankAccountName"
+                         min-width="170"
+                         show-overflow-tooltip />
+        <el-table-column label="璐﹀彿"
+                         prop="bankAccountNum"
+                         min-width="170"
+                         show-overflow-tooltip />
+        <el-table-column label="鑱旂郴浜�"
+                         prop="contactUserName"
+                         min-width="90"
+                         show-overflow-tooltip />
+        <el-table-column label="鑱旂郴鐢佃瘽"
+                         prop="contactUserPhone"
+                         min-width="130"
+                         show-overflow-tooltip />
+        <el-table-column label="鏄惁鐧藉悕鍗�"
+                         prop="isWhite"
+                         align="center"
+                         width="100">
+          <template #default="scope">
+            <el-tag :type="scope.row.isWhite === 1 ? 'success' : 'info'"
+                    size="small">
+              {{ scope.row.isWhite === 1 ? "鏄�" : "鍚�" }}
+            </el-tag>
+          </template>
+        </el-table-column>
+        <el-table-column label="缁存姢浜�"
+                         prop="maintainUserName"
+                         min-width="90"
+                         show-overflow-tooltip />
+        <el-table-column label="缁存姢鏃堕棿"
+                         prop="maintainTime"
+                         min-width="110"
+                         show-overflow-tooltip />
+        <el-table-column label="澶囨敞"
+                         prop="remark"
+                         min-width="140"
+                         show-overflow-tooltip />
+        <el-table-column fixed="right"
+                         label="鎿嶄綔"
+                         width="160"
+                         align="center">
+          <template #default="scope">
+            <el-button link
+                       type="primary"
+                       @click="openForm('edit', scope.row)">缂栬緫</el-button>
+            <el-button link
+                       type="primary"
+                       @click="openAttachment(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-on-click-modal="false"
+               @close="closeDia">
+      <el-form :model="form"
+               label-width="140px"
+               label-position="top"
+               :rules="rules"
+               ref="formRef">
+        <el-row :gutter="30">
+          <el-col :span="12">
+            <el-form-item label="鍚堜綔鍟嗗悕绉帮細"
+                          prop="partnerName">
+              <el-input v-model="form.partnerName"
+                        placeholder="璇疯緭鍏�"
+                        clearable />
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="绾崇◣浜鸿瘑鍒彿锛�"
+                          prop="taxpayerIdentificationNum">
+              <el-input v-model="form.taxpayerIdentificationNum"
+                        placeholder="璇疯緭鍏�"
+                        clearable />
+            </el-form-item>
+          </el-col>
+        </el-row>
+        <el-row :gutter="30">
+          <el-col :span="12">
+            <el-form-item label="鍏徃鍦板潃锛�"
+                          prop="companyAddress">
+              <el-input v-model="form.companyAddress"
+                        placeholder="璇疯緭鍏�"
+                        clearable />
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="鍏徃鐢佃瘽锛�"
+                          prop="companyPhone">
+              <el-input v-model="form.companyPhone"
+                        placeholder="璇疯緭鍏�"
+                        clearable />
+            </el-form-item>
+          </el-col>
+        </el-row>
+        <el-row :gutter="30">
+          <el-col :span="12">
+            <el-form-item label="寮�鎴疯锛�"
+                          prop="bankAccountName">
+              <el-input v-model="form.bankAccountName"
+                        placeholder="璇疯緭鍏�"
+                        clearable />
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="璐﹀彿锛�"
+                          prop="bankAccountNum">
+              <el-input v-model="form.bankAccountNum"
+                        placeholder="璇疯緭鍏�"
+                        clearable />
+            </el-form-item>
+          </el-col>
+        </el-row>
+        <el-row :gutter="30">
+          <el-col :span="12">
+            <el-form-item label="鑱旂郴浜猴細"
+                          prop="contactUserName">
+              <el-input v-model="form.contactUserName"
+                        placeholder="璇疯緭鍏�"
+                        clearable />
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="鑱旂郴鐢佃瘽锛�"
+                          prop="contactUserPhone">
+              <el-input v-model="form.contactUserPhone"
+                        placeholder="璇疯緭鍏�"
+                        clearable />
+            </el-form-item>
+          </el-col>
+        </el-row>
+        <el-row :gutter="30">
+          <el-col :span="12">
+            <el-form-item label="鍚堜綔鍟嗙被鍨嬶細"
+                          prop="partnerType">
+              <el-input v-model="form.partnerType"
+                        placeholder="璇疯緭鍏ワ紝濡傦細鍗卞簾澶勭疆"
+                        clearable />
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="鏄惁鐧藉悕鍗曪細"
+                          prop="isWhite">
+              <el-select v-model="form.isWhite"
+                         placeholder="璇烽�夋嫨"
+                         clearable
+                         style="width: 100%">
+                <el-option label="鏄�"
+                           :value="1" />
+                <el-option label="鍚�"
+                           :value="0" />
+              </el-select>
+            </el-form-item>
+          </el-col>
+        </el-row>
+        <el-row :gutter="30">
+          <el-col :span="24">
+            <el-form-item label="澶囨敞锛�"
+                          prop="remark">
+              <el-input v-model="form.remark"
+                        type="textarea"
+                        :rows="2"
+                        placeholder="璇疯緭鍏�"
+                        clearable />
+            </el-form-item>
+          </el-col>
+        </el-row>
+        <el-row :gutter="30">
+          <el-col :span="24">
+            <el-form-item label="闄勪欢锛�">
+              <AttachmentUploadFile v-model:file-list="partnerFileList"
+                                    :limit="10" />
+            </el-form-item>
+          </el-col>
+        </el-row>
+      </el-form>
+      <template #footer>
+        <div class="dialog-footer">
+          <el-button type="primary"
+                     @click="submitForm">纭</el-button>
+          <el-button @click="closeDia">鍙栨秷</el-button>
+        </div>
+      </template>
+    </el-dialog>
+    <!-- 瀵煎叆瀵硅瘽妗� -->
+    <el-dialog :title="upload.title"
+               v-model="upload.open"
+               width="400px"
+               append-to-body>
+      <el-upload ref="uploadRef"
+                 :limit="1"
+                 accept=".xlsx, .xls"
+                 :headers="upload.headers"
+                 :action="upload.url"
+                 :disabled="upload.isUploading"
+                 :on-progress="handleFileUploadProgress"
+                 :on-success="handleFileSuccess"
+                 :on-error="handleFileError"
+                 :auto-upload="false"
+                 drag>
+        <el-icon class="el-icon--upload">
+          <upload-filled />
+        </el-icon>
+        <div class="el-upload__text">灏嗘枃浠舵嫋鍒版澶勶紝鎴�<em>鐐瑰嚮涓婁紶</em></div>
+        <template #tip>
+          <div class="el-upload__tip text-center">
+            <span>浠呭厑璁稿鍏ls銆亁lsx鏍煎紡鏂囦欢銆�</span>
+            <el-link type="primary"
+                     :underline="false"
+                     style="font-size: 12px; vertical-align: baseline"
+                     @click="importTemplate">涓嬭浇妯℃澘</el-link>
+          </div>
+        </template>
+      </el-upload>
+      <template #footer>
+        <div class="dialog-footer">
+          <el-button type="primary"
+                     @click="submitFileForm">纭� 瀹�</el-button>
+          <el-button @click="upload.open = false">鍙� 娑�</el-button>
+        </div>
+      </template>
+    </el-dialog>
+    <!-- 闄勪欢锛氬彲鐩存帴涓婁紶/鍒犻櫎锛屾敼鍔ㄥ嵆鏃朵繚瀛樺埌璇ュ悎浣滃晢 -->
+    <el-dialog v-model="attachmentVisible"
+               title="闄勪欢"
+               width="600px"
+               append-to-body>
+      <div v-loading="attachmentLoading"
+           style="min-height: 140px">
+        <AttachmentUploadFile v-model:file-list="attachmentList"
+                              :limit="10"
+                              @change="saveAttachments" />
+      </div>
+    </el-dialog>
+  </div>
+</template>
+
+<script setup>
+  import { ref, reactive, toRefs, getCurrentInstance, onMounted } from "vue";
+  import pagination from "@/components/PIMTable/Pagination.vue";
+  import AttachmentUploadFile from "@/components/AttachmentUpload/file/index.vue";
+  import { ElMessageBox } from "element-plus";
+  import { getToken } from "@/utils/auth.js";
+  import {
+    listPartner,
+    getPartner,
+    addPartner,
+    updatePartner,
+    delPartner,
+    exportPartner,
+    downloadPartnerTemplate,
+  } from "@/api/outsourcing/partner.js";
+
+  const { proxy } = getCurrentInstance();
+  const tableData = ref([]);
+  const selectedRows = ref([]);
+  const tableLoading = ref(false);
+  const dialogFormVisible = ref(false);
+  const attachmentVisible = ref(false);
+  const attachmentList = ref([]);
+  const attachmentLoading = ref(false);
+  // 闄勪欢寮规瀵瑰簲鐨勫悎浣滃晢璇︽儏锛氬垪琛ㄨ瀛楁涓嶅叏锛屼繚瀛樻椂鐢ㄨ鎯呴噷鐨勫瓧娈垫暣浣撳洖浼�
+  const attachmentDetail = ref({});
+  const operationType = ref("");
+  const page = reactive({
+    current: 1,
+    size: 10,
+  });
+  const total = ref(0);
+
+  const data = reactive({
+    searchForm: {
+      partnerName: "",
+      partnerType: "",
+      isWhite: "",
+    },
+    form: {},
+    rules: {
+      partnerName: [{ required: true, message: "璇疯緭鍏ュ悎浣滃晢鍚嶇О", trigger: "blur" }],
+    },
+  });
+  const { searchForm, form, rules } = toRefs(data);
+  // 闄勪欢闅忚〃鍗曚竴骞舵彁浜わ紝鍚庣鎸� storageBlobDTOS 鍏ㄩ噺瑕嗙洊锛屾竻绌哄嵆瑙g粦
+  const partnerFileList = ref([]);
+
+  // 鍚堜綔鍟嗙被鍨嬬瓑瀛楁鍚庣鏈粰瀛楀吀锛岀被鍨嬫寜鑷敱鏂囨湰缁存姢
+  const buildEmptyForm = () => ({
+    id: null,
+    partnerName: "",
+    taxpayerIdentificationNum: "",
+    companyAddress: "",
+    companyPhone: "",
+    bankAccountName: "",
+    bankAccountNum: "",
+    contactUserName: "",
+    contactUserPhone: "",
+    partnerType: "",
+    isWhite: 0,
+    remark: "",
+  });
+
+  // 鍘绘帀绌哄�硷紝閬垮厤 isWhite='' 杩欑被绌轰覆琚悗绔綋鎴� 0 瑙f瀽
+  const compact = obj =>
+    Object.fromEntries(
+      Object.entries(obj).filter(([, v]) => v !== "" && v !== null && v !== undefined)
+    );
+
+  const getList = () => {
+    tableLoading.value = true;
+    listPartner({
+      pageNum: page.current,
+      pageSize: page.size,
+      ...compact(searchForm.value),
+    })
+      .then(res => {
+        tableLoading.value = false;
+        tableData.value = res.data?.records || [];
+        total.value = res.data?.total || 0;
+      })
+      .catch(() => {
+        tableLoading.value = false;
+      });
+  };
+
+  const handleQuery = () => {
+    page.current = 1;
+    getList();
+  };
+
+  const paginationChange = obj => {
+    page.current = obj.page;
+    page.size = obj.limit;
+    getList();
+  };
+
+  const handleSelectionChange = selection => {
+    selectedRows.value = selection;
+  };
+
+  const openForm = (type, row) => {
+    operationType.value = type;
+    form.value = buildEmptyForm();
+    partnerFileList.value = [];
+    proxy.resetForm("formRef");
+    dialogFormVisible.value = true;
+    if (type === "edit" && row) {
+      // 璇︽儏杩斿洖鐨勯檮浠跺彲鑳芥槸 storageBlobVOS 鎴� storageBlobDTOS锛屽洖鏄惧悗缁熶竴杞垚 storageBlobDTOS 鍏ㄩ噺鎻愪氦
+      getPartner(row.id).then(res => {
+        const { storageBlobVOS, storageBlobDTOS, ...detail } = res.data || {};
+        form.value = { ...buildEmptyForm(), ...detail };
+        partnerFileList.value = storageBlobVOS || storageBlobDTOS || [];
+      });
+    }
+  };
+
+  // 鍙彁浜ゆ枃妗g害瀹氱殑瀛楁锛岀淮鎶や汉/缁存姢鏃堕棿/鍒涘缓鏃堕棿绛夌敱鍚庣缁存姢
+  // source/files 鍙紶鍙傦細闄勪欢寮规淇濆瓨鏃剁敤鐨勬槸璇︽儏鏁版嵁 + 寮规鍐呯殑闄勪欢鍒楄〃
+  const buildPayload = (source = form.value, files = partnerFileList.value) => {
+    const {
+      id,
+      partnerName,
+      taxpayerIdentificationNum,
+      companyAddress,
+      companyPhone,
+      bankAccountName,
+      bankAccountNum,
+      contactUserName,
+      contactUserPhone,
+      partnerType,
+      isWhite,
+      remark,
+    } = source || {};
+    return {
+      partnerName,
+      taxpayerIdentificationNum,
+      companyAddress,
+      companyPhone,
+      bankAccountName,
+      bankAccountNum,
+      contactUserName,
+      contactUserPhone,
+      partnerType,
+      isWhite,
+      remark,
+      storageBlobDTOS: (files || [])
+        .filter(item => item && item.id != null)
+        .map(item => ({ id: item.id })),
+      ...(id ? { id } : {}),
+    };
+  };
+
+  const submitForm = () => {
+    proxy.$refs["formRef"].validate(valid => {
+      if (valid) {
+        const api = form.value.id ? updatePartner : addPartner;
+        api(buildPayload()).then(() => {
+          proxy.$modal.msgSuccess("鎿嶄綔鎴愬姛");
+          closeDia();
+          getList();
+        });
+      }
+    });
+  };
+
+  const closeDia = () => {
+    proxy.resetForm("formRef");
+    partnerFileList.value = [];
+    dialogFormVisible.value = false;
+  };
+
+  // 鍏堝脊妗嗗啀鎷夐檮浠讹細璇︽儏鎺ュ彛鎱㈡垨澶辫触鏃讹紝鎸夐挳涔熶笉浼氱湅璧锋潵鍍忔病鍙嶅簲
+  const openAttachment = row => {
+    attachmentList.value = [];
+    attachmentDetail.value = {};
+    attachmentVisible.value = true;
+    attachmentLoading.value = true;
+    getPartner(row.id)
+      .then(res => {
+        attachmentDetail.value = res.data || {};
+        // 鍚堜綔鍟嗚鎯呭悗绔妸闄勪欢鏀惧湪 storageBlobDTOS锛堝叾瀹冩ā鍧楃殑 VO 鎵嶅彨 storageBlobVOS锛夛紝涓や釜閮藉厹浣�
+        attachmentList.value = res.data?.storageBlobVOS || res.data?.storageBlobDTOS || [];
+      })
+      .catch(() => {
+        attachmentList.value = [];
+      })
+      .finally(() => {
+        attachmentLoading.value = false;
+      });
+  };
+
+  // 寮规鍐呬笂浼�/鍒犻櫎鍚庣珛鍗充繚瀛橈細鍚庣鎸� storageBlobDTOS 鍏ㄩ噺瑕嗙洊锛屾墍浠ユ暣浠藉垪琛ㄥ洖浼�
+  const saveAttachments = files => {
+    const list = Array.isArray(files) ? files : attachmentList.value;
+    attachmentList.value = list;
+    if (!attachmentDetail.value?.id) {
+      proxy.$modal.msgError("鏈幏鍙栧埌鍚堜綔鍟嗕俊鎭紝闄勪欢淇濆瓨澶辫触");
+      return;
+    }
+    attachmentLoading.value = true;
+    updatePartner(buildPayload(attachmentDetail.value, list))
+      .then(() => {
+        attachmentDetail.value = {
+          ...attachmentDetail.value,
+          storageBlobDTOS: list,
+        };
+        proxy.$modal.msgSuccess("闄勪欢宸蹭繚瀛�");
+      })
+      .finally(() => {
+        attachmentLoading.value = false;
+      });
+  };
+
+  const handleDelete = () => {
+    if (selectedRows.value.length === 0) {
+      proxy.$modal.msgWarning("璇烽�夋嫨鏁版嵁");
+      return;
+    }
+    const ids = selectedRows.value.map(item => item.id);
+    ElMessageBox.confirm(
+      "閫変腑鐨勫唴瀹瑰皢琚垹闄わ紝鏄惁纭鍒犻櫎锛熷凡瀛樺湪濮斿璁㈠崟鎴栧線鏉ユ敹浠樻璁板綍鐨勫悎浣滃晢涓嶅厑璁稿垹闄ゃ��",
+      "鍒犻櫎",
+      {
+        confirmButtonText: "纭",
+        cancelButtonText: "鍙栨秷",
+        type: "warning",
+      }
+    )
+      .then(() => {
+        delPartner(ids).then(() => {
+          proxy.$modal.msgSuccess("鍒犻櫎鎴愬姛");
+          getList();
+        });
+      })
+      .catch(() => {
+        proxy.$modal.msg("宸插彇娑�");
+      });
+  };
+
+  // 淇濆瓨 Excel 鏂囦欢娴�
+  const saveExcelBlob = (data, filename) => {
+    const blob = new Blob([data], {
+      type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
+    });
+    const url = window.URL.createObjectURL(blob);
+    const link = document.createElement("a");
+    link.href = url;
+    link.download = filename;
+    document.body.appendChild(link);
+    link.click();
+    setTimeout(() => {
+      document.body.removeChild(link);
+      window.URL.revokeObjectURL(url);
+    }, 100);
+  };
+
+  const handleExport = () => {
+    ElMessageBox.confirm("鏄惁纭瀵煎嚭锛�", "瀵煎嚭", {
+      confirmButtonText: "纭",
+      cancelButtonText: "鍙栨秷",
+      type: "warning",
+    })
+      .then(() => {
+        exportPartner(compact(searchForm.value)).then(res => {
+          saveExcelBlob(res, "鍚堜綔鍟嗘。妗�.xlsx");
+        });
+      })
+      .catch(() => {
+        proxy.$modal.msg("宸插彇娑�");
+      });
+  };
+
+  const upload = reactive({
+    open: false,
+    title: "",
+    isUploading: false,
+    headers: { Authorization: "Bearer " + getToken() },
+    url: import.meta.env.VITE_APP_BASE_API + "/outsourcing/partner/import",
+  });
+
+  const handleImport = () => {
+    upload.title = "鍚堜綔鍟嗗鍏�";
+    upload.open = true;
+  };
+
+  const importTemplate = () => {
+    downloadPartnerTemplate().then(res => {
+      saveExcelBlob(res, "鍚堜綔鍟嗗鍏ユā鏉�.xlsx");
+    });
+  };
+
+  const handleFileUploadProgress = () => {
+    upload.isUploading = true;
+  };
+
+  const handleFileSuccess = response => {
+    upload.isUploading = false;
+    if (response.code === 200) {
+      proxy.$modal.msgSuccess("鏂囦欢涓婁紶鎴愬姛");
+      upload.open = false;
+      proxy.$refs["uploadRef"].clearFiles();
+      getList();
+    } else {
+      proxy.$modal.msgError(response.msg);
+    }
+  };
+
+  const handleFileError = () => {
+    upload.isUploading = false;
+    proxy.$modal.msgError("鏂囦欢涓婁紶澶辫触");
+  };
+
+  const submitFileForm = () => {
+    upload.isUploading = true;
+    proxy.$refs["uploadRef"].submit();
+  };
+
+  onMounted(() => {
+    getList();
+  });
+</script>
+
+<style scoped lang="scss">
+  .search_form {
+    margin-bottom: 16px;
+  }
+
+  .actions {
+    display: flex;
+    justify-content: flex-end;
+    margin-bottom: 12px;
+  }
+</style>
diff --git a/src/views/outsourcingManagement/transactions/index.vue b/src/views/outsourcingManagement/transactions/index.vue
new file mode 100644
index 0000000..ed08afc
--- /dev/null
+++ b/src/views/outsourcingManagement/transactions/index.vue
@@ -0,0 +1,255 @@
+<template>
+  <div class="app-container">
+    <div class="search_form"
+         style="margin-bottom: 20px;">
+      <span class="search_title">鍚堜綔鍟嗗悕绉帮細</span>
+      <el-input v-model="searchForm.partnerName"
+                style="width: 240px"
+                placeholder="杈撳叆鍚堜綔鍟嗗悕绉�"
+                @change="handleQuery"
+                clearable
+                :prefix-icon="Search" />
+      <el-button type="primary"
+                 @click="handleQuery"
+                 style="margin-left: 10px">鎼滅储</el-button>
+    </div>
+    <el-row :gutter="20">
+      <el-col :span="14">
+        <div class="table_list">
+          <el-table border
+                    v-loading="tableLoading"
+                    :data="tableData"
+                    highlight-current-row
+                    style="width: 100%"
+                    height="calc(100vh - 18.5em)"
+                    @row-click="rowClick">
+            <el-table-column align="center"
+                             label="搴忓彿"
+                             type="index"
+                             width="60" />
+            <el-table-column label="鍚堜綔鍟嗗悕绉�"
+                             prop="partnerName"
+                             min-width="180"
+                             show-overflow-tooltip />
+            <el-table-column label="鍚堝悓閲戦(鍏�)"
+                             prop="contractAmounts"
+                             min-width="130">
+              <template #default="scope">
+                {{ formatAmount(scope.row.contractAmounts) }}
+              </template>
+            </el-table-column>
+            <el-table-column label="浠樻閲戦(鍏�)"
+                             prop="paidAmount"
+                             min-width="130">
+              <template #default="scope">
+                {{ formatAmount(scope.row.paidAmount) }}
+              </template>
+            </el-table-column>
+            <el-table-column label="搴斾粯閲戦(鍏�)"
+                             prop="payableAmount"
+                             min-width="130">
+              <template #default="scope">
+                <el-text type="danger">{{ formatAmount(scope.row.payableAmount) }}</el-text>
+              </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-col>
+      <el-col :span="10">
+        <div class="table_list">
+          <div class="detail-tip">
+            搴斾粯浣欓 = 宸茬‘璁�/宸插畬鎴愮殑濮斿璁㈠崟閲戦 鈭� 宸蹭粯娆撅紱鏄庣粏姣忚鐨勩�屽凡浠樻銆嶄负鍚堜綔鍟嗙骇鍚堣锛岄潪璁㈠崟绾с��
+          </div>
+          <el-table border
+                    v-loading="detailLoading"
+                    :data="detailTableData"
+                    style="width: 100%"
+                    height="calc(100vh - 21em)">
+            <el-table-column align="center"
+                             label="搴忓彿"
+                             type="index"
+                             width="60" />
+            <el-table-column label="濮斿璁㈠崟鍙�"
+                             prop="orderNo"
+                             min-width="150"
+                             show-overflow-tooltip />
+            <el-table-column label="鐢宠鏃ユ湡"
+                             prop="applyDate"
+                             min-width="110"
+                             show-overflow-tooltip />
+            <el-table-column label="璁㈠崟閲戦(鍏�)"
+                             prop="contractAmount"
+                             min-width="120">
+              <template #default="scope">
+                {{ formatAmount(scope.row.contractAmount) }}
+              </template>
+            </el-table-column>
+            <el-table-column label="鐘舵��"
+                             prop="status"
+                             align="center"
+                             width="90">
+              <template #default="scope">
+                <el-tag :type="statusTagType(scope.row.status)"
+                        size="small">
+                  {{ statusLabel(scope.row.status) }}
+                </el-tag>
+              </template>
+            </el-table-column>
+            <el-table-column label="鍚堜綔鍟嗗凡浠樻(鍏�)"
+                             prop="paidAmount"
+                             min-width="140">
+              <template #default="scope">
+                {{ formatAmount(scope.row.paidAmount) }}
+              </template>
+            </el-table-column>
+            <el-table-column label="搴斾粯閲戦(鍏�)"
+                             prop="payableAmount"
+                             min-width="120">
+              <template #default="scope">
+                <el-text type="danger">{{ formatAmount(scope.row.payableAmount) }}</el-text>
+              </template>
+            </el-table-column>
+            <el-table-column fixed="right"
+                             label="鎿嶄綔"
+                             width="110"
+                             align="center">
+              <template #default="scope">
+                <el-button link
+                           type="primary"
+                           @click.stop="openPaymentDialog(scope.row)">鏂板浠樻</el-button>
+              </template>
+            </el-table-column>
+          </el-table>
+        </div>
+      </el-col>
+    </el-row>
+    <PaymentRecordDialog v-model:visible="paymentDialogVisible"
+                         title="鍚堜綔鍟嗕粯娆炬祦姘�"
+                         :party-type="3"
+                         :party-id="paymentPartyId"
+                         :party-name="paymentPartyName"
+                         :direction="1"
+                         @changed="refreshAll" />
+  </div>
+</template>
+
+<script setup>
+  import { ref, reactive, toRefs } from "vue";
+  import { Search } from "@element-plus/icons-vue";
+  import pagination from "@/components/PIMTable/Pagination.vue";
+  import PaymentRecordDialog from "@/components/PaymentRecordDialog/index.vue";
+  import {
+    partnerTransactions,
+    partnerTransactionsDetails,
+  } from "@/api/outsourcing/report.js";
+
+  const tableData = ref([]);
+  const detailTableData = ref([]);
+  const tableLoading = ref(false);
+  const detailLoading = ref(false);
+  const total = ref(0);
+  const page = reactive({ current: 1, size: 10 });
+  const currentPartnerId = ref("");
+
+  const paymentDialogVisible = ref(false);
+  const paymentPartyId = ref("");
+  const paymentPartyName = ref("");
+
+  const statusLabelMap = { 0: "鑽夌", 1: "宸茬‘璁�", 2: "宸插畬鎴�", 3: "宸蹭綔搴�" };
+  const statusTagMap = { 0: "info", 1: "primary", 2: "success", 3: "danger" };
+  const statusLabel = status => statusLabelMap[status] ?? status;
+  const statusTagType = status => statusTagMap[status] || "info";
+
+  const data = reactive({
+    searchForm: {
+      partnerName: "",
+    },
+  });
+  const { searchForm } = toRefs(data);
+
+  const formatAmount = value => {
+    const num = Number(value);
+    return Number.isFinite(num) ? num.toFixed(2) : "0.00";
+  };
+
+  const getList = () => {
+    tableLoading.value = true;
+    partnerTransactions({
+      pageNum: page.current,
+      pageSize: page.size,
+      ...searchForm.value,
+    })
+      .then(res => {
+        tableLoading.value = false;
+        tableData.value = res.data?.records || [];
+        total.value = res.data?.total || 0;
+      })
+      .catch(() => {
+        tableLoading.value = false;
+      });
+  };
+
+  const getDetailList = partnerId => {
+    if (!partnerId) {
+      detailTableData.value = [];
+      return;
+    }
+    detailLoading.value = true;
+    partnerTransactionsDetails(partnerId)
+      .then(res => {
+        detailLoading.value = false;
+        detailTableData.value = res.data?.records || [];
+      })
+      .catch(() => {
+        detailLoading.value = false;
+      });
+  };
+
+  const handleQuery = () => {
+    page.current = 1;
+    getList();
+  };
+
+  const paginationChange = obj => {
+    page.current = obj.page;
+    page.size = obj.limit;
+    getList();
+  };
+
+  const rowClick = row => {
+    currentPartnerId.value = row.partnerId;
+    getDetailList(row.partnerId);
+  };
+
+  const openPaymentDialog = row => {
+    paymentPartyId.value = row.partnerId;
+    paymentPartyName.value = row.partnerName || "";
+    paymentDialogVisible.value = true;
+  };
+
+  const refreshAll = () => {
+    getList();
+    getDetailList(currentPartnerId.value);
+  };
+
+  getList();
+</script>
+
+<style scoped lang="scss">
+  .detail-tip {
+    margin-bottom: 10px;
+    padding: 8px 12px;
+    font-size: 12px;
+    line-height: 1.6;
+    color: #909399;
+    background: rgba(64, 158, 255, 0.08);
+    border-left: 3px solid #409eff;
+    border-radius: 3px;
+  }
+</style>
diff --git a/src/views/procurementManagement/paymentLedger/index.vue b/src/views/procurementManagement/paymentLedger/index.vue
index 7fba9cb..1478399 100644
--- a/src/views/procurementManagement/paymentLedger/index.vue
+++ b/src/views/procurementManagement/paymentLedger/index.vue
@@ -46,17 +46,31 @@
                              prop="paymentAmount"
                              show-overflow-tooltip
                              :formatter="formattedNumber" />
-            <el-table-column label="閫�璐ч噾棰�(鍏�)"
-                             prop="returnAmount"
-                             show-overflow-tooltip
-                             :formatter="formattedNumber" />
+<!--            <el-table-column label="鍥炴閲戦(鍏�)"-->
+<!--                             prop="receiptAmount"-->
+<!--                             show-overflow-tooltip-->
+<!--                             :formatter="formattedNumber" />-->
+<!--            <el-table-column label="閫�璐ч噾棰�(鍏�)"-->
+<!--                             prop="returnAmount"-->
+<!--                             show-overflow-tooltip-->
+<!--                             :formatter="formattedNumber" />-->
             <el-table-column label="搴斾粯閲戦(鍏�)"
-                             prop="payableAmount"
+                             prop="paymentRecordAmount"
                              show-overflow-tooltip>
               <template #default="{ row, column }">
                 <el-text type="danger">
-                  {{ formattedNumber(row, column, row.payableAmount) }}
+                  {{ formattedNumber(row, column, row.paymentRecordAmount) }}
                 </el-text>
+              </template>
+            </el-table-column>
+            <el-table-column label="鎿嶄綔"
+                             align="center"
+                             width="90"
+                             fixed="right">
+              <template #default="{ row }">
+                <el-button link
+                           type="primary"
+                           @click.stop="openRecordDialog(row)">娴佹按</el-button>
               </template>
             </el-table-column>
           </el-table>
@@ -90,6 +104,14 @@
         </div>
       </el-col>
     </el-row>
+    <!-- 渚涘簲鍟嗗洖娆炬祦姘寸淮鎶� -->
+    <PaymentRecordDialog v-model:visible="recordDialogVisible"
+                         title="渚涘簲鍟嗗洖娆炬祦姘�"
+                         :party-type="2"
+                         :party-id="recordPartyId"
+                         :party-name="recordPartyName"
+                         :direction="2"
+                         @changed="getList" />
   </div>
 </template>
 
@@ -101,6 +123,7 @@
     paymentRecordList,
   } from "@/api/procurementManagement/paymentLedger.js";
   import Pagination from "../../../components/PIMTable/Pagination.vue";
+  import PaymentRecordDialog from "@/components/PaymentRecordDialog/index.vue";
 
   const tableData = ref([]);
   const tableLoading = ref(false);
@@ -123,6 +146,16 @@
   const isShowSummary = ref(true);
   const { searchForm } = toRefs(data);
   const currentSupplierId = ref("");
+  // 鍥炴娴佹按寮圭獥
+  const recordDialogVisible = ref(false);
+  const recordPartyId = ref("");
+  const recordPartyName = ref("");
+
+  const openRecordDialog = row => {
+    recordPartyId.value = row.supplierId;
+    recordPartyName.value = row.supplierName || "";
+    recordDialogVisible.value = true;
+  };
   const rowClick = row => {
     currentSupplierId.value = row.supplierId;
     sonPage.current = 1;
@@ -156,19 +189,28 @@
         return params ? parseFloat(params).toFixed(2) : 0;
       },
     },
-    {
-      label: "閫�璐ч噾棰�(鍏�)",
-      prop: "returnAmount",
-      width: 200,
-      formatData: params => {
-        return params ? parseFloat(params).toFixed(2) : 0;
-      },
-    },
+    // 寰�鏉ユ柟缁村害鍚堣锛屾槑缁嗗悇琛屽悓鍊硷紝鏁呬笉鍙備笌鍚堣琛�
+    // {
+    //   label: "鍥炴閲戦(鍏�)",
+    //   prop: "receiptAmount",
+    //   width: 200,
+    //   formatData: params => {
+    //     return params ? parseFloat(params).toFixed(2) : 0;
+    //   },
+    // },
+    // {
+    //   label: "閫�璐ч噾棰�(鍏�)",
+    //   prop: "returnAmount",
+    //   width: 200,
+    //   formatData: params => {
+    //     return params ? parseFloat(params).toFixed(2) : 0;
+    //   },
+    // },
     {
       label: "搴斾粯閲戦(鍏�)",
       dataType: "slot",
       width: 200,
-      prop: "payableAmount",
+      prop: "paymentRecordAmount",
       slot: "payableAmountSlot",
     },
   ]);
@@ -182,7 +224,7 @@
   const summarizeMainTable = param => {
     return proxy.summarizeTable(
       param,
-      ["contractAmounts", "paymentAmount", "returnAmount", "payableAmount"],
+      ["contractAmounts", "paymentAmount", "receiptAmount", "returnAmount", "payableAmount"],
       {
         ticketsNum: { noDecimal: true }, // 涓嶄繚鐣欏皬鏁�
         futureTickets: { noDecimal: true }, // 涓嶄繚鐣欏皬鏁�
diff --git a/src/views/procurementManagement/purchaseApplication/index.vue b/src/views/procurementManagement/purchaseApplication/index.vue
new file mode 100644
index 0000000..a9cf71f
--- /dev/null
+++ b/src/views/procurementManagement/purchaseApplication/index.vue
@@ -0,0 +1,1087 @@
+<template>
+  <div class="app-container">
+    <div class="search_form">
+      <div>
+        <el-form :model="searchForm"
+                 :inline="true">
+          <el-form-item label="鐢宠鍗曞彿锛�">
+            <el-input v-model="searchForm.applicationNo"
+                      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-select v-model="searchForm.supplierId"
+                       placeholder="璇烽�夋嫨"
+                       filterable
+                       clearable
+                       style="width: 240px"
+                       @change="handleQuery">
+              <el-option v-for="item in supplierOptions"
+                         :key="item.id"
+                         :label="item.supplierName"
+                         :value="item.id" />
+            </el-select>
+          </el-form-item>
+          <el-form-item label="鐘舵�侊細">
+            <el-select v-model="searchForm.status"
+                       placeholder="璇烽�夋嫨"
+                       clearable
+                       style="width: 160px"
+                       @change="handleQuery">
+              <el-option label="鑽夌"
+                         :value="0" />
+              <el-option label="宸茬敓鎴愯鍗�"
+                         :value="1" />
+            </el-select>
+          </el-form-item>
+          <el-form-item label="鐢宠鏃ユ湡锛�">
+            <el-date-picker v-model="searchForm.applyDate"
+                            value-format="YYYY-MM-DD"
+                            format="YYYY-MM-DD"
+                            type="daterange"
+                            placeholder="璇烽�夋嫨"
+                            clearable
+                            @change="changeDaterange" />
+          </el-form-item>
+          <el-form-item>
+            <el-button type="primary"
+                       @click="handleQuery"> 鎼滅储 </el-button>
+          </el-form-item>
+        </el-form>
+      </div>
+    </div>
+    <div class="table_list">
+      <div style="display: flex;justify-content: flex-end;margin-bottom: 20px;">
+        <el-button type="primary"
+                   @click="openForm('add')">鏂板鐢宠鍗�</el-button>
+        <el-button type="danger"
+                   plain
+                   @click="handleDelete()">鍒犻櫎</el-button>
+      </div>
+      <el-table :data="tableData"
+                border
+                v-loading="tableLoading"
+                @selection-change="handleSelectionChange"
+                :row-key="(row) => row.id"
+                show-summary
+                :summary-method="summarizeMainTable"
+                height="calc(100vh - 21.5em)">
+        <el-table-column align="center"
+                         type="selection"
+                         width="55"
+                         :selectable="row => row.status === 0" />
+        <el-table-column align="center"
+                         label="搴忓彿"
+                         type="index"
+                         width="60" />
+        <el-table-column label="鐢宠鍗曞彿"
+                         prop="applicationNo"
+                         width="170"
+                         show-overflow-tooltip />
+        <el-table-column label="渚涘簲鍟嗗悕绉�"
+                         prop="supplierName"
+                         width="200"
+                         show-overflow-tooltip />
+        <el-table-column label="椤圭洰鍚嶇О"
+                         prop="projectName"
+                         width="280"
+                         show-overflow-tooltip />
+        <el-table-column label="閿�鍞悎鍚屽彿"
+                         prop="salesContractNo"
+                         width="170"
+                         show-overflow-tooltip />
+        <el-table-column label="鐢宠浜�"
+                         prop="applicantName"
+                         width="100"
+                         show-overflow-tooltip />
+        <el-table-column label="鐢宠鏃ユ湡"
+                         prop="applyDate"
+                         width="110"
+                         show-overflow-tooltip />
+        <el-table-column label="鏈熸湜鍒拌揣鏃ユ湡"
+                         prop="expectedArrivalDate"
+                         width="130"
+                         show-overflow-tooltip />
+        <el-table-column label="鍚堝悓閲戦(鍏�)"
+                         prop="contractAmount"
+                         width="140"
+                         show-overflow-tooltip
+                         :formatter="formattedNumber" />
+        <el-table-column label="浠樻鏂瑰紡"
+                         prop="paymentMethod"
+                         width="100"
+                         show-overflow-tooltip />
+        <el-table-column label="鐘舵��"
+                         prop="status"
+                         width="110"
+                         align="center">
+          <template #default="scope">
+            <el-tag :type="scope.row.status === 1 ? 'success' : 'info'"
+                    size="small">
+              {{ statusText[scope.row.status] || '--' }}
+            </el-tag>
+          </template>
+        </el-table-column>
+        <el-table-column label="澶囨敞"
+                         prop="remarks"
+                         width="200"
+                         show-overflow-tooltip />
+        <el-table-column fixed="right"
+                         label="鎿嶄綔"
+                         width="200"
+                         align="center">
+          <template #default="scope">
+            <template v-if="scope.row.status === 0">
+              <el-button link
+                         type="primary"
+                         @click="openForm('edit', scope.row)">缂栬緫</el-button>
+              <el-button link
+                         type="primary"
+                         @click="handleConvert(scope.row)">杞鍗�</el-button>
+              <el-button link
+                         type="danger"
+                         @click="handleDelete(scope.row)">鍒犻櫎</el-button>
+            </template>
+            <el-button v-else
+                       link
+                       type="primary"
+                       @click="openForm('detail', 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>
+    <FormDialog v-model="dialogFormVisible"
+                :title="dialogTitle"
+                :width="'70%'"
+                :operation-type="operationType"
+                @close="closeDia"
+                @confirm="submitForm"
+                @cancel="closeDia">
+      <el-form :model="form"
+               :disabled="isDetail"
+               label-width="140px"
+               label-position="top"
+               :rules="rules"
+               ref="formRef">
+        <el-row :gutter="30">
+          <el-col :span="12">
+            <el-form-item label="鐢宠鍗曞彿锛�"
+                          prop="applicationNo">
+              <el-input v-model="form.applicationNo"
+                        placeholder="淇濆瓨鍚庤嚜鍔ㄧ敓鎴�"
+                        disabled />
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="鐢宠鏃ユ湡锛�"
+                          prop="applyDate">
+              <el-date-picker style="width: 100%"
+                              v-model="form.applyDate"
+                              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="12">
+            <el-form-item label="渚涘簲鍟嗗悕绉帮細"
+                          prop="supplierId">
+              <el-select v-model="form.supplierId"
+                         placeholder="璇烽�夋嫨"
+                         filterable
+                         clearable
+                         style="width: 100%">
+                <el-option v-for="item in supplierList"
+                           :key="item.id"
+                           :label="item.supplierName"
+                           :value="item.id" />
+              </el-select>
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="椤圭洰鍚嶇О"
+                          prop="projectName">
+              <el-input v-model="form.projectName"
+                        placeholder="璇疯緭鍏�"
+                        clearable />
+            </el-form-item>
+          </el-col>
+        </el-row>
+        <el-row :gutter="30">
+          <el-col :span="12">
+            <el-form-item label="閿�鍞悎鍚屽彿锛�"
+                          prop="salesLedgerId">
+              <el-select v-model="form.salesLedgerId"
+                         placeholder="璇烽�夋嫨"
+                         filterable
+                         clearable
+                         style="width: 100%"
+                         @change="salesLedgerChange">
+                <el-option v-for="item in salesContractList"
+                           :key="item.id"
+                           :label="item.salesContractNo"
+                           :value="item.id" />
+              </el-select>
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="鐢宠浜猴細"
+                          prop="applicantId">
+              <el-select v-model="form.applicantId"
+                         placeholder="涓嶉�夊垯榛樿涓哄綋鍓嶇櫥褰曠敤鎴�"
+                         filterable
+                         clearable
+                         style="width: 100%">
+                <el-option v-for="item in userList"
+                           :key="item.userId"
+                           :label="item.nickName"
+                           :value="item.userId" />
+              </el-select>
+            </el-form-item>
+          </el-col>
+        </el-row>
+        <el-row :gutter="30">
+          <el-col :span="8">
+            <el-form-item label="鏈熸湜鍒拌揣鏃ユ湡锛�"
+                          prop="expectedArrivalDate">
+              <el-date-picker style="width: 100%"
+                              v-model="form.expectedArrivalDate"
+                              value-format="YYYY-MM-DD"
+                              format="YYYY-MM-DD"
+                              type="date"
+                              placeholder="璇烽�夋嫨"
+                              clearable />
+            </el-form-item>
+          </el-col>
+          <el-col :span="8">
+            <el-form-item label="鍚堝悓閲戦(鍏�)锛�"
+                          prop="contractAmount">
+              <el-input-number v-model="form.contractAmount"
+                               :precision="2"
+                               :step="0.1"
+                               :min="0"
+                               placeholder="璇疯緭鍏�"
+                               style="width: 100%" />
+            </el-form-item>
+          </el-col>
+          <el-col :span="8">
+            <el-form-item label="浠樻鏂瑰紡锛�"
+                          prop="paymentMethod">
+              <el-input v-model="form.paymentMethod"
+                        placeholder="璇疯緭鍏�"
+                        clearable />
+            </el-form-item>
+          </el-col>
+        </el-row>
+        <el-row>
+          <el-form-item label="浜у搧淇℃伅锛�">
+            <el-button v-if="!isDetail"
+                       type="primary"
+                       @click="openProductForm('add')">娣诲姞</el-button>
+            <el-button v-if="!isDetail"
+                       plain
+                       type="danger"
+                       @click="deleteProduct">鍒犻櫎</el-button>
+          </el-form-item>
+        </el-row>
+        <el-table :data="productData"
+                  border
+                  @selection-change="productSelected"
+                  show-summary
+                  :summary-method="summarizeProTable">
+          <el-table-column align="center"
+                           type="selection"
+                           width="55"
+                           :selectable="() => !isDetail" />
+          <el-table-column align="center"
+                           label="搴忓彿"
+                           type="index"
+                           width="60" />
+          <el-table-column label="浜у搧澶х被"
+                           prop="productCategory"
+                           show-overflow-tooltip />
+          <el-table-column label="瑙勬牸鍨嬪彿"
+                           prop="specificationModel"
+                           show-overflow-tooltip />
+          <el-table-column label="鍗曚綅"
+                           prop="unit"
+                           width="70" />
+          <el-table-column label="鏁伴噺"
+                           prop="quantity"
+                           width="80" />
+          <el-table-column label="绋庣巼(%)"
+                           prop="taxRate"
+                           width="80" />
+          <el-table-column label="鍚◣鍗曚环(鍏�)"
+                           prop="taxInclusiveUnitPrice"
+                           width="120"
+                           :formatter="formattedNumber" />
+          <el-table-column label="鍚◣鎬讳环(鍏�)"
+                           prop="taxInclusiveTotalPrice"
+                           width="120"
+                           :formatter="formattedNumber" />
+          <el-table-column label="涓嶅惈绋庢�讳环(鍏�)"
+                           prop="taxExclusiveTotalPrice"
+                           width="130"
+                           :formatter="formattedNumber" />
+          <el-table-column label="鍙戠エ绫诲瀷"
+                           prop="invoiceType"
+                           width="110"
+                           show-overflow-tooltip />
+          <el-table-column label="鏄惁璐ㄦ"
+                           prop="isChecked"
+                           width="90">
+            <template #default="scope">
+              <el-tag :type="scope.row.isChecked ? 'success' : 'info'"
+                      size="small">
+                {{ scope.row.isChecked ? '鏄�' : '鍚�' }}
+              </el-tag>
+            </template>
+          </el-table-column>
+          <el-table-column label="澶囨敞"
+                           prop="remark"
+                           show-overflow-tooltip />
+          <el-table-column v-if="!isDetail"
+                           fixed="right"
+                           label="鎿嶄綔"
+                           width="80"
+                           align="center">
+            <template #default="scope">
+              <el-button link
+                         type="primary"
+                         @click="openProductForm('edit', scope.row, scope.$index)">缂栬緫
+              </el-button>
+            </template>
+          </el-table-column>
+        </el-table>
+        <el-row :gutter="30">
+          <el-col :span="24">
+            <el-form-item label="澶囨敞锛�"
+                          prop="remarks">
+              <el-input v-model="form.remarks"
+                        placeholder="璇疯緭鍏�"
+                        clearable
+                        type="textarea"
+                        :rows="2" />
+            </el-form-item>
+          </el-col>
+        </el-row>
+      </el-form>
+    </FormDialog>
+    <FormDialog v-model="productFormVisible"
+                :title="productOperationType === 'add' ? '鏂板浜у搧' : '缂栬緫浜у搧'"
+                :width="'40%'"
+                :operation-type="productOperationType"
+                @close="closeProductDia"
+                @confirm="submitProduct"
+                @cancel="closeProductDia">
+      <el-form :model="productForm"
+               label-width="140px"
+               label-position="top"
+               :rules="productRules"
+               ref="productFormRef">
+        <el-row :gutter="30">
+          <el-col :span="24">
+            <el-form-item label="浜у搧澶х被锛�"
+                          prop="productId">
+              <el-tree-select v-model="productForm.productId"
+                              placeholder="璇烽�夋嫨"
+                              clearable
+                              filterable
+                              check-strictly
+                              @change="getModels"
+                              :data="productOptions"
+                              :render-after-expand="false"
+                              style="width: 100%" />
+            </el-form-item>
+          </el-col>
+        </el-row>
+        <el-row :gutter="30">
+          <el-col :span="24">
+            <el-form-item label="瑙勬牸鍨嬪彿锛�"
+                          prop="productModelId">
+              <el-select v-model="productForm.productModelId"
+                         placeholder="璇烽�夋嫨"
+                         filterable
+                         clearable
+                         style="width: 100%"
+                         @change="getProductModel">
+                <el-option v-for="item in modelOptions"
+                           :key="item.id"
+                           :label="item.model"
+                           :value="item.id" />
+              </el-select>
+            </el-form-item>
+          </el-col>
+        </el-row>
+        <el-row :gutter="30">
+          <el-col :span="12">
+            <el-form-item label="鍗曚綅锛�"
+                          prop="unit">
+              <el-input v-model="productForm.unit"
+                        placeholder="璇疯緭鍏�"
+                        clearable />
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="绋庣巼(%)锛�"
+                          prop="taxRate">
+              <el-select v-model="productForm.taxRate"
+                         placeholder="璇烽�夋嫨"
+                         clearable
+                         style="width: 100%"
+                         @change="calcTotals">
+                <el-option v-for="dict in tax_rate"
+                           :key="dict.value"
+                           :label="dict.label"
+                           :value="dict.value" />
+              </el-select>
+            </el-form-item>
+          </el-col>
+        </el-row>
+        <el-row :gutter="30">
+          <el-col :span="12">
+            <el-form-item label="鍚◣鍗曚环(鍏�)锛�"
+                          prop="taxInclusiveUnitPrice">
+              <el-input-number v-model="productForm.taxInclusiveUnitPrice"
+                               :precision="2"
+                               :step="0.1"
+                               :min="0"
+                               style="width: 100%"
+                               @change="calcTotals" />
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="鏁伴噺锛�"
+                          prop="quantity">
+              <el-input-number v-model="productForm.quantity"
+                               :precision="2"
+                               :step="0.1"
+                               :min="0"
+                               placeholder="璇疯緭鍏�"
+                               style="width: 100%"
+                               @change="calcTotals" />
+            </el-form-item>
+          </el-col>
+        </el-row>
+        <el-row :gutter="30">
+          <el-col :span="12">
+            <el-form-item label="鍚◣鎬讳环(鍏�)锛�"
+                          prop="taxInclusiveTotalPrice">
+              <el-input-number v-model="productForm.taxInclusiveTotalPrice"
+                               :precision="2"
+                               disabled
+                               style="width: 100%" />
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="涓嶅惈绋庢�讳环(鍏�)锛�"
+                          prop="taxExclusiveTotalPrice">
+              <el-input-number v-model="productForm.taxExclusiveTotalPrice"
+                               :precision="2"
+                               disabled
+                               style="width: 100%" />
+            </el-form-item>
+          </el-col>
+        </el-row>
+        <el-row :gutter="30">
+          <el-col :span="12">
+            <el-form-item label="鍙戠エ绫诲瀷锛�"
+                          prop="invoiceType">
+              <el-select v-model="productForm.invoiceType"
+                         placeholder="璇烽�夋嫨"
+                         clearable
+                         style="width: 100%">
+                <el-option label="澧炴櫘绁�"
+                           value="澧炴櫘绁�" />
+                <el-option label="澧炰笓绁�"
+                           value="澧炰笓绁�" />
+              </el-select>
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="鏄惁璐ㄦ锛�"
+                          prop="isChecked">
+              <el-radio-group v-model="productForm.isChecked">
+                <el-radio label="鏄�"
+                          :value="true" />
+                <el-radio label="鍚�"
+                          :value="false" />
+              </el-radio-group>
+            </el-form-item>
+          </el-col>
+        </el-row>
+        <el-row :gutter="30">
+          <el-col :span="24">
+            <el-form-item label="澶囨敞锛�"
+                          prop="remark">
+              <el-input v-model="productForm.remark"
+                        placeholder="璇疯緭鍏�"
+                        clearable />
+            </el-form-item>
+          </el-col>
+        </el-row>
+      </el-form>
+    </FormDialog>
+  </div>
+</template>
+
+<script setup>
+  import FormDialog from "@/components/Dialog/FormDialog.vue";
+  import pagination from "@/components/PIMTable/Pagination.vue";
+  import {
+    ref,
+    reactive,
+    toRefs,
+    computed,
+    getCurrentInstance,
+    nextTick,
+    onMounted,
+  } from "vue";
+  import { ElMessage, ElMessageBox } from "element-plus";
+  import { Search } from "@element-plus/icons-vue";
+  import dayjs from "dayjs";
+  import router from "@/router";
+  import usePermissionStore from "@/store/modules/permission";
+  import {
+    applicationList,
+    getApplicationById,
+    addApplication,
+    editApplication,
+    delApplication,
+    convertToOrder,
+  } from "@/api/procurementManagement/purchaseApplication.js";
+  import {
+    getSalesNo,
+    getOptions,
+  } from "@/api/procurementManagement/procurementLedger.js";
+  import { modelList, productTreeList } from "@/api/basicData/product.js";
+  import { userListNoPage } from "@/api/system/user.js";
+
+  const { proxy } = getCurrentInstance();
+  const { tax_rate } = proxy.useDict("tax_rate");
+  const permissionStore = usePermissionStore();
+
+  const statusText = {
+    0: "鑽夌",
+    1: "宸茬敓鎴愯鍗�",
+  };
+
+  const tableData = ref([]);
+  const productData = ref([]);
+  const selectedRows = ref([]);
+  const productSelectedRows = ref([]);
+  const supplierOptions = ref([]);
+  const supplierList = ref([]);
+  const salesContractList = ref([]);
+  const userList = ref([]);
+  const productOptions = ref([]);
+  const modelOptions = ref([]);
+  const tableLoading = ref(false);
+  const dialogFormVisible = ref(false);
+  const productFormVisible = ref(false);
+  const operationType = ref("");
+  const productOperationType = ref("");
+  const productOperationIndex = ref("");
+  const currentId = ref("");
+  const total = ref(0);
+  const page = reactive({ current: 1, size: 10 });
+
+  const isDetail = computed(() => operationType.value === "detail");
+  const dialogTitle = computed(() => {
+    if (operationType.value === "add") return "鏂板閲囪喘鐢宠";
+    if (operationType.value === "edit") return "缂栬緫閲囪喘鐢宠";
+    return "閲囪喘鐢宠璇︽儏";
+  });
+
+  const searchForm = reactive({
+    applicationNo: "",
+    projectName: "",
+    supplierId: "",
+    status: "",
+    applyDate: null,
+    startDate: undefined,
+    endDate: undefined,
+  });
+
+  const data = reactive({
+    form: {
+      id: "",
+      applicationNo: "",
+      supplierId: "",
+      projectName: "",
+      salesContractNo: "",
+      salesLedgerId: "",
+      applicantId: "",
+      applyDate: "",
+      expectedArrivalDate: "",
+      contractAmount: "",
+      paymentMethod: "",
+      remarks: "",
+    },
+    rules: {
+      applyDate: [{ required: true, message: "璇烽�夋嫨", trigger: "change" }],
+    },
+  });
+  const { form, rules } = toRefs(data);
+
+  const productFormData = reactive({
+    productForm: {
+      productId: "",
+      productCategory: "",
+      productModelId: "",
+      specificationModel: "",
+      unit: "",
+      quantity: "",
+      taxRate: "",
+      taxInclusiveUnitPrice: "",
+      taxInclusiveTotalPrice: "",
+      taxExclusiveTotalPrice: "",
+      invoiceType: "",
+      isChecked: false,
+      remark: "",
+    },
+    productRules: {
+      productId: [{ required: true, message: "璇烽�夋嫨", trigger: "change" }],
+      productModelId: [{ required: true, message: "璇烽�夋嫨", trigger: "change" }],
+      unit: [{ required: true, message: "璇疯緭鍏�", trigger: "blur" }],
+      quantity: [{ required: true, message: "璇疯緭鍏�", trigger: "blur" }],
+      taxRate: [{ required: true, message: "璇烽�夋嫨", trigger: "change" }],
+      taxInclusiveUnitPrice: [
+        { required: true, message: "璇疯緭鍏�", trigger: "blur" },
+      ],
+    },
+  });
+  const { productForm, productRules } = toRefs(productFormData);
+
+  const formattedNumber = (row, column, cellValue) => {
+    if (cellValue === null || cellValue === undefined || cellValue === "") {
+      return "--";
+    }
+    return Number(cellValue).toFixed(2);
+  };
+
+  const changeDaterange = value => {
+    if (value) {
+      searchForm.startDate = dayjs(value[0]).format("YYYY-MM-DD");
+      searchForm.endDate = dayjs(value[1]).format("YYYY-MM-DD");
+    } else {
+      searchForm.startDate = undefined;
+      searchForm.endDate = undefined;
+    }
+    handleQuery();
+  };
+
+  const handleQuery = () => {
+    page.current = 1;
+    getList();
+  };
+
+  const paginationChange = obj => {
+    page.current = obj.page;
+    page.size = obj.limit;
+    getList();
+  };
+
+  const getList = () => {
+    tableLoading.value = true;
+    const { applyDate, ...rest } = searchForm;
+    applicationList({ ...rest, pageNum: page.current, pageSize: page.size })
+      .then(res => {
+        const rows = res.rows || res.data?.rows || res.data?.records || [];
+        tableData.value = rows;
+        total.value = res.total ?? res.data?.total ?? 0;
+      })
+      .catch(() => {
+        tableData.value = [];
+        total.value = 0;
+      })
+      .finally(() => {
+        tableLoading.value = false;
+      });
+  };
+
+  const handleSelectionChange = selection => {
+    selectedRows.value = selection;
+  };
+
+  const productSelected = selection => {
+    productSelectedRows.value = selection;
+  };
+
+  const summarizeMainTable = param => {
+    return proxy.summarizeTable(param, ["contractAmount"]);
+  };
+
+  const summarizeProTable = param => {
+    return proxy.summarizeTable(param, [
+      "taxInclusiveUnitPrice",
+      "taxInclusiveTotalPrice",
+      "taxExclusiveTotalPrice",
+    ]);
+  };
+
+  // 渚涘簲鍟嗕笅鎷夛細绛涢�夌敤鍏ㄩ噺锛岃〃鍗曚粎鍙�夌櫧鍚嶅崟渚涘簲鍟嗭紙涓庨噰璐彴璐︿竴鑷达級
+  const getSupplierOptions = async () => {
+    const res = await getOptions();
+    const list = res.data || [];
+    supplierOptions.value = list;
+    supplierList.value = list.filter(item => item.isWhite === 0);
+  };
+
+  const getSalesContractList = async () => {
+    const res = await getSalesNo();
+    salesContractList.value = Array.isArray(res) ? res : res?.data || [];
+  };
+
+  const getUserList = async () => {
+    const res = await userListNoPage();
+    userList.value = res.data || [];
+  };
+
+  const getProductOptions = async () => {
+    const res = await productTreeList();
+    productOptions.value = convertIdToValue(res || []);
+  };
+
+  function convertIdToValue(list) {
+    return list.map(item => {
+      const { id, children, ...rest } = item;
+      const newItem = { ...rest, value: id };
+      if (children && children.length > 0) {
+        newItem.children = convertIdToValue(children);
+      }
+      return newItem;
+    });
+  }
+
+  const findNodeLabelById = (nodes, value) => {
+    for (const node of nodes) {
+      if (node.value === value) {
+        return node.label;
+      }
+      if (node.children && node.children.length > 0) {
+        const found = findNodeLabelById(node.children, value);
+        if (found) return found;
+      }
+    }
+    return "";
+  };
+
+  const findNodeValueByLabel = (nodes, label) => {
+    for (const node of nodes) {
+      if (node.label === label) {
+        return node.value;
+      }
+      if (node.children && node.children.length > 0) {
+        const found = findNodeValueByLabel(node.children, label);
+        if (found) return found;
+      }
+    }
+    return "";
+  };
+
+  const getModels = value => {
+    if (!value) {
+      productForm.value.productCategory = "";
+      modelOptions.value = [];
+      return Promise.resolve([]);
+    }
+    productForm.value.productCategory = findNodeLabelById(
+      productOptions.value,
+      value
+    );
+    return modelList({ id: value }).then(res => {
+      modelOptions.value = res || [];
+      return res;
+    });
+  };
+
+  const getProductModel = value => {
+    const matched = modelOptions.value.find(item => item.id === value);
+    if (matched) {
+      productForm.value.specificationModel = matched.model;
+      productForm.value.unit = matched.unit;
+    } else {
+      productForm.value.specificationModel = "";
+      productForm.value.unit = "";
+    }
+  };
+
+  // 鍚◣鎬讳环 = 鍚◣鍗曚环 脳 鏁伴噺锛涗笉鍚◣鎬讳环鐢卞惈绋庢�讳环涓庣◣鐜囧弽绠�
+  const calcTotals = () => {
+    const { taxInclusiveUnitPrice, quantity, taxRate } = productForm.value;
+    if (!taxInclusiveUnitPrice && taxInclusiveUnitPrice !== 0) return;
+    if (!quantity && quantity !== 0) return;
+    productForm.value.taxInclusiveTotalPrice =
+      proxy.calculateTaxIncludeTotalPrice(taxInclusiveUnitPrice, quantity);
+    if (taxRate) {
+      productForm.value.taxExclusiveTotalPrice =
+        proxy.calculateTaxExclusiveTotalPrice(
+          productForm.value.taxInclusiveTotalPrice,
+          taxRate
+        );
+    }
+  };
+
+  const openProductForm = async (type, row, index) => {
+    productOperationType.value = type;
+    productOperationIndex.value = index;
+    productForm.value = {};
+    proxy.resetForm("productFormRef");
+    productFormVisible.value = true;
+
+    if (productOptions.value.length === 0) {
+      await getProductOptions();
+    }
+    await nextTick();
+
+    if (type === "add") {
+      productForm.value.isChecked = false;
+      return;
+    }
+
+    productForm.value = { ...row };
+    if (!productForm.value.productId && productForm.value.productCategory) {
+      productForm.value.productId = findNodeValueByLabel(
+        productOptions.value,
+        productForm.value.productCategory
+      );
+    }
+    if (productForm.value.productId) {
+      await getModels(productForm.value.productId);
+      await nextTick();
+      if (productForm.value.productModelId) {
+        getProductModel(productForm.value.productModelId);
+      }
+    }
+  };
+
+  const submitProduct = () => {
+    proxy.$refs["productFormRef"].validate(valid => {
+      if (!valid) return;
+      if (productOperationType.value === "add") {
+        productData.value.push({ ...productForm.value });
+      } else {
+        productData.value[productOperationIndex.value] = {
+          ...productForm.value,
+        };
+      }
+      closeProductDia();
+    });
+  };
+
+  const deleteProduct = () => {
+    if (productSelectedRows.value.length === 0) {
+      proxy.$modal.msgWarning("璇烽�夋嫨鏁版嵁");
+      return;
+    }
+    productData.value = productData.value.filter(
+      item => !productSelectedRows.value.includes(item)
+    );
+    productSelectedRows.value = [];
+  };
+
+  const closeProductDia = () => {
+    proxy.resetForm("productFormRef");
+    productFormVisible.value = false;
+  };
+
+  const salesLedgerChange = value => {
+    const matched = salesContractList.value.find(item => item.id === value);
+    form.value.salesContractNo = matched ? matched.salesContractNo : "";
+  };
+
+  const openForm = async (type, row) => {
+    operationType.value = type;
+    currentId.value = row?.id || "";
+    proxy.resetForm("formRef");
+    form.value = {
+      id: "",
+      applicationNo: "",
+      supplierId: "",
+      projectName: "",
+      salesContractNo: "",
+      salesLedgerId: "",
+      applicantId: "",
+      applyDate: dayjs().format("YYYY-MM-DD"),
+      expectedArrivalDate: "",
+      contractAmount: "",
+      paymentMethod: "",
+      remarks: "",
+    };
+    productData.value = [];
+    productSelectedRows.value = [];
+
+    try {
+      await Promise.all([
+        getSupplierOptions(),
+        getSalesContractList(),
+        getUserList(),
+        getProductOptions(),
+      ]);
+    } catch (error) {
+      proxy.$modal.msgError("鍔犺浇鍩虹鏁版嵁澶辫触");
+      return;
+    }
+
+    if (type === "add") {
+      dialogFormVisible.value = true;
+      return;
+    }
+
+    try {
+      const res = await getApplicationById({ id: row.id });
+      form.value = { ...(res.data || {}), id: row.id };
+      productData.value = res.data?.productData || [];
+    } catch (error) {
+      proxy.$modal.msgError("鍔犺浇閲囪喘鐢宠璇︽儏澶辫触");
+      return;
+    }
+    dialogFormVisible.value = true;
+  };
+
+  const closeDia = () => {
+    proxy.resetForm("formRef");
+    dialogFormVisible.value = false;
+  };
+
+  // 鍙彁浜ゅ悗绔厑璁哥殑瀛楁锛岃嚜鍔ㄥ瓧娈碉紙鍗曞彿銆佺姸鎬併�佺鎴风瓑锛変竴寰嬩笉浼�
+  const buildPayload = () => {
+    const payload = {
+      supplierId: form.value.supplierId || null,
+      projectName: form.value.projectName,
+      salesContractNo: form.value.salesContractNo,
+      salesLedgerId: form.value.salesLedgerId || null,
+      applyDate: form.value.applyDate,
+      expectedArrivalDate: form.value.expectedArrivalDate || null,
+      contractAmount:
+        form.value.contractAmount === "" ? null : form.value.contractAmount,
+      paymentMethod: form.value.paymentMethod,
+      remarks: form.value.remarks,
+      productData: productData.value.map(
+        ({ id, purchaseApplicationId, ...rest }) => rest
+      ),
+    };
+    // 鐢宠浜虹暀绌鸿〃绀虹敱鍚庣鍙栧綋鍓嶇櫥褰曠敤鎴�
+    if (form.value.applicantId) {
+      payload.applicantId = form.value.applicantId;
+    }
+    return payload;
+  };
+
+  const submitForm = () => {
+    proxy.$refs["formRef"].validate(async valid => {
+      if (!valid) return;
+      const payload = buildPayload();
+      try {
+        if (operationType.value === "add") {
+          await addApplication(payload);
+        } else {
+          await editApplication({ id: currentId.value, ...payload });
+        }
+        proxy.$modal.msgSuccess("淇濆瓨鎴愬姛");
+        closeDia();
+        getList();
+      } catch (error) {
+        // 閿欒淇℃伅鐢� request 鎷︽埅鍣ㄧ粺涓�鎻愮ず
+      }
+    });
+  };
+
+  const handleDelete = row => {
+    let ids = [];
+    if (row) {
+      ids = [row.id];
+    } else if (selectedRows.value.length > 0) {
+      ids = selectedRows.value.map(item => item.id);
+    } else {
+      proxy.$modal.msgWarning("璇烽�夋嫨鏁版嵁");
+      return;
+    }
+    ElMessageBox.confirm("閫変腑鐨勫唴瀹瑰皢琚垹闄わ紝鏄惁纭鍒犻櫎锛�", "鍒犻櫎", {
+      confirmButtonText: "纭",
+      cancelButtonText: "鍙栨秷",
+      type: "warning",
+    })
+      .then(async () => {
+        await delApplication(ids);
+        proxy.$modal.msgSuccess("鍒犻櫎鎴愬姛");
+        getList();
+      })
+      .catch(() => {});
+  };
+
+  const handleConvert = row => {
+    ElMessageBox.confirm(
+      `纭灏嗙敵璇峰崟銆�${row.applicationNo}銆嶈浆涓洪噰璐鍗曞悧锛熻浆璁㈠崟鍚庡皢鑷姩鎻愪氦閲囪喘瀹℃壒銆俙,
+      "杞鍗�",
+      {
+        confirmButtonText: "纭",
+        cancelButtonText: "鍙栨秷",
+        type: "warning",
+      }
+    )
+      .then(async () => {
+        const res = await convertToOrder(row.id);
+        getList();
+        ElMessageBox.confirm(
+          `杞鍗曟垚鍔燂紝宸茬敓鎴愰噰璐彴璐︼紙id锛�${res.data}锛夈�傛槸鍚﹀墠寰�閲囪喘鍙拌处鏌ョ湅锛焋,
+          "鎻愮ず",
+          {
+            confirmButtonText: "鍓嶅線鏌ョ湅",
+            cancelButtonText: "鐣欏湪鏈〉",
+            type: "success",
+          }
+        )
+          .then(() => {
+            const path = findLedgerPath(permissionStore.sidebarRouters);
+            if (path) {
+              router.push(path);
+            } else {
+              ElMessage.info("璇峰墠寰�銆岄噰璐彴璐︺�嶆煡鐪嬬敓鎴愮殑璁㈠崟");
+            }
+          })
+          .catch(() => {});
+      })
+      .catch(() => {});
+  };
+
+  // 浠庝晶杈规爮鑿滃崟涓畾浣嶉噰璐彴璐﹁矾鐢憋紝鎵句笉鍒版椂涓嶈烦杞粎鎻愮ず
+  const findLedgerPath = (routes, prefix = "") => {
+    for (const route of routes || []) {
+      const fullPath = String(route.path || "").startsWith("/")
+        ? route.path
+        : `${prefix}/${route.path || ""}`;
+      if (route.meta?.title === "閲囪喘鍙拌处") {
+        return fullPath;
+      }
+      const found = findLedgerPath(route.children, fullPath);
+      if (found) return found;
+    }
+    return "";
+  };
+
+  onMounted(() => {
+    getList();
+    getSupplierOptions();
+  });
+</script>
diff --git a/src/views/procurementManagement/transferManagement/index.vue b/src/views/procurementManagement/transferManagement/index.vue
index 3646449..afa1c12 100644
--- a/src/views/procurementManagement/transferManagement/index.vue
+++ b/src/views/procurementManagement/transferManagement/index.vue
@@ -191,9 +191,9 @@
     });
     // 浣跨敤 Promise.all 澶勭悊鎵�鏈夊紓姝ヨ姹�
     const processedOrders = await Promise.all(response.data.records.map(async (order) => {
-      // 绛夊緟寮傛鑾峰彇浜у搧璁板綍
+      // 绛夊緟寮傛鑾峰彇浜у搧璁板綍锛堟寜閲囪喘鍙拌处id绮剧‘鍙嶆樉锛屽悎鍚屽彿鍙兘閲嶅/涓虹┖锛�
       const productRes = await selectProductRecordListByPuechaserId({
-        purchaseContractNumber: order.purchaseContractNumber
+        purchaseLedgerId: order.id
       });
 
       // 纭繚 productRes.data 瀛樺湪
@@ -317,9 +317,9 @@
 {
   try {
     loadingProducts.value = true
-    // 鏍规嵁鍚堝悓鏌ヨ浜у搧璁板綍
+    // 鏍规嵁閲囪喘鍙拌处id鏌ヨ浜у搧璁板綍
     const productRes = await selectProductRecordListByPuechaserId({
-      purchaseContractNumber: receiptForm.value.purchaseContractNumber
+      purchaseLedgerId: receiptForm.value.purchaseLedgerId
     });
     console.log('productRes:', productRes)
     operationType.value = 'add'
diff --git a/src/views/salesManagement/deliveryLedger/index.vue b/src/views/salesManagement/deliveryLedger/index.vue
index 33fa45f..e8eaeae 100644
--- a/src/views/salesManagement/deliveryLedger/index.vue
+++ b/src/views/salesManagement/deliveryLedger/index.vue
@@ -2,7 +2,17 @@
   <div class="app-container">
     <div class="search_form">
       <el-form :model="searchForm" :inline="true">
-        <el-form-item label="閿�鍞鍗曞彿锛�">
+        <el-form-item label="鍙戣揣鍗曞彿锛�">
+          <el-input
+            v-model="searchForm.shippingNo"
+            placeholder="璇疯緭鍏�"
+            clearable
+            prefix-icon="Search"
+            style="width: 200px"
+            @change="handleQuery"
+          />
+        </el-form-item>
+        <el-form-item label="閿�鍞悎鍚屽彿锛�">
           <el-input
             v-model="searchForm.salesContractNo"
             placeholder="璇疯緭鍏�"
@@ -15,16 +25,6 @@
         <el-form-item label="杞︾墝鍙凤細">
           <el-input
             v-model="searchForm.shippingCarNumber"
-            placeholder="璇疯緭鍏�"
-            clearable
-            prefix-icon="Search"
-            style="width: 200px"
-            @change="handleQuery"
-          />
-        </el-form-item>
-        <el-form-item label="蹇�掑崟鍙凤細">
-          <el-input
-            v-model="searchForm.expressNumber"
             placeholder="璇疯緭鍏�"
             clearable
             prefix-icon="Search"
@@ -50,17 +50,27 @@
         border
         v-loading="tableLoading"
         @selection-change="handleSelectionChange"
-        :row-key="(row) => row.id"
+        :row-key="(row) => `${row.source || 'shipping'}-${row.stockOutRecordId ?? row.id}`"
         style="width: 100%"
         height="calc(100vh - 21.5em)"
       >
-        <el-table-column align="center" type="selection" width="55" />
-        <el-table-column align="center" label="搴忓彿" type="index" width="60" />
         <el-table-column
-          label="閿�鍞鍗�"
-          prop="salesContractNo"
-          show-overflow-tooltip
+          align="center"
+          type="selection"
+          :selectable="isRowSelectable"
+          width="55"
         />
+        <el-table-column align="center" label="搴忓彿" type="index" width="60" />
+        <el-table-column label="鏉ユ簮" prop="source" align="center" width="100">
+          <template #default="scope">
+            <el-tag
+              :type="isOilOutRow(scope.row) ? 'success' : 'info'"
+              size="small"
+            >
+              {{ isOilOutRow(scope.row) ? "娌瑰搧鍑哄簱" : "鍙戣揣鍗�" }}
+            </el-tag>
+          </template>
+        </el-table-column>
         <el-table-column
           label="鍙戣揣璁㈠崟鍙�"
           prop="shippingNo"
@@ -72,6 +82,16 @@
           show-overflow-tooltip
         />
         <el-table-column
+          label="瀹㈡埛瀵规帴浜�"
+          prop="contactPerson"
+          show-overflow-tooltip
+        />
+        <el-table-column
+          label="瀵规帴浜虹數璇�"
+          prop="contactPhone"
+          show-overflow-tooltip
+        />
+        <el-table-column
           label="浜у搧鍚嶇О"
           prop="productName"
           show-overflow-tooltip
@@ -79,6 +99,27 @@
         <el-table-column
           label="瑙勬牸鍨嬪彿"
           prop="specificationModel"
+          show-overflow-tooltip
+        />
+        <el-table-column label="鎵瑰彿" show-overflow-tooltip>
+          <!-- 娌瑰搧鍑哄簱琛岀殑鎵瑰彿鏄� outBatchNo锛坆atch_no锛夛紝鍙戣揣鍗曡娌℃湁璇ュ瓧娈� -->
+          <template #default="scope">
+            {{
+              isOilOutRow(scope.row)
+                ? scope.row.outBatchNo || "--"
+                : scope.row.batchNo || "--"
+            }}
+          </template>
+        </el-table-column>
+        <el-table-column
+          label="鍑哄簱绫诲埆"
+          prop="outCategory"
+          show-overflow-tooltip
+        />
+        <el-table-column label="鍌ㄧ綈鍙�" prop="tankNo" show-overflow-tooltip />
+        <el-table-column
+          label="娌瑰簱"
+          prop="oilDepotName"
           show-overflow-tooltip
         />
         <el-table-column
@@ -97,13 +138,8 @@
           show-overflow-tooltip
         />
         <el-table-column
-          label="蹇�掑叕鍙�"
-          prop="expressCompany"
-          show-overflow-tooltip
-        />
-        <el-table-column
-          label="蹇�掑崟鍙�"
-          prop="expressNumber"
+          label="鍙告満濮撳悕"
+          prop="driverName"
           show-overflow-tooltip
         />
         <el-table-column
@@ -173,21 +209,6 @@
       >
         <el-row :gutter="30">
           <el-col :span="24">
-            <el-form-item label="鍙戣揣绫诲瀷锛�" prop="type">
-              <el-select
-                v-model="form.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%"
@@ -202,31 +223,11 @@
           </el-col>
         </el-row>
         <el-row :gutter="30">
-          <el-col :span="24" v-if="form.type === '璐ц溅'">
+          <el-col :span="24">
             <el-form-item label="鍙戣揣杞︾墝鍙凤細" prop="shippingCarNumber">
               <el-input
                 v-model="form.shippingCarNumber"
                 placeholder="璇疯緭鍏ュ彂璐ц溅鐗屽彿"
-                clearable
-              />
-            </el-form-item>
-          </el-col>
-          <el-col :span="24" v-else>
-            <el-form-item label="蹇�掑叕鍙革細" prop="expressCompany">
-              <el-input
-                v-model="form.expressCompany"
-                placeholder="璇疯緭鍏ュ揩閫掑叕鍙�"
-                clearable
-              />
-            </el-form-item>
-          </el-col>
-        </el-row>
-        <el-row :gutter="30" v-if="form.type === '蹇��'">
-          <el-col :span="24">
-            <el-form-item label="蹇�掑崟鍙凤細" prop="expressNumber">
-              <el-input
-                v-model="form.expressNumber"
-                placeholder="璇疯緭鍏ュ揩閫掑崟鍙�"
                 clearable
               />
             </el-form-item>
@@ -257,14 +258,17 @@
     >
       <div v-if="detailRow" class="detail-wrapper">
         <el-descriptions :column="2" border>
-          <el-descriptions-item label="閿�鍞鍗�">{{
-            detailRow.salesContractNo || "--"
-          }}</el-descriptions-item>
           <el-descriptions-item label="鍙戣揣璁㈠崟鍙�">{{
             detailRow.shippingNo || "--"
           }}</el-descriptions-item>
           <el-descriptions-item label="瀹㈡埛鍚嶇О">{{
             detailRow.customerName || "--"
+          }}</el-descriptions-item>
+          <el-descriptions-item label="瀹㈡埛瀵规帴浜�">{{
+            detailRow.contactPerson || "--"
+          }}</el-descriptions-item>
+          <el-descriptions-item label="瀵规帴浜虹數璇�">{{
+            detailRow.contactPhone || "--"
           }}</el-descriptions-item>
           <el-descriptions-item label="浜у搧鍚嶇О">{{
             detailRow.productName || "--"
@@ -272,8 +276,14 @@
           <el-descriptions-item label="瑙勬牸鍨嬪彿">{{
             detailRow.specificationModel || "--"
           }}</el-descriptions-item>
-          <el-descriptions-item label="鍙戣揣绫诲瀷">{{
-            detailRow.type || "--"
+          <el-descriptions-item label="鍑哄簱绫诲埆">{{
+            detailRow.outCategory || "--"
+          }}</el-descriptions-item>
+          <el-descriptions-item label="鍌ㄧ綈鍙�">{{
+            detailRow.tankNo || "--"
+          }}</el-descriptions-item>
+          <el-descriptions-item label="娌瑰簱">{{
+            detailRow.oilDepotName || "--"
           }}</el-descriptions-item>
           <el-descriptions-item label="鍙戣揣鏃ユ湡">{{
             detailRow.shippingDate || "--"
@@ -284,11 +294,8 @@
           <el-descriptions-item label="鍙戣揣杞︾墝鍙�">{{
             detailRow.shippingCarNumber || "--"
           }}</el-descriptions-item>
-          <el-descriptions-item label="蹇�掑叕鍙�">{{
-            detailRow.expressCompany || "--"
-          }}</el-descriptions-item>
-          <el-descriptions-item label="蹇�掑崟鍙�" :span="2">{{
-            detailRow.expressNumber || "--"
+          <el-descriptions-item label="鍙告満濮撳悕">{{
+            detailRow.driverName || "--"
           }}</el-descriptions-item>
           <el-descriptions-item label="鍑哄簱鍗曞彿" :span="2">{{
             detailRow.outboundBatches || "--"
@@ -321,7 +328,7 @@
           />
           <el-table-column
             label="鍙戣揣鏁伴噺"
-            prop="deliveryQuantity"
+            prop="totalQuantity"
             min-width="120"
             align="center"
           />
@@ -356,7 +363,6 @@
 const tableData = ref([]);
 const selectedRows = ref([]);
 const tableLoading = ref(false);
-const salesOrderOptions = ref([]);
 const page = reactive({
   current: 1,
   size: 100,
@@ -373,46 +379,27 @@
 const dialogFormVisible = ref(false);
 const data = reactive({
   searchForm: {
-    salesContractNo: "", // 閿�鍞鍗曞彿
+    shippingNo: "", // 鍙戣揣鍗曞彿锛堜袱绫绘潵婧愰兘鍖归厤锛�
+    salesContractNo: "", // 閿�鍞悎鍚屽彿锛堝彧鍖归厤鍙戣揣鍗曡锛�
     shippingCarNumber: "", // 杞︾墝鍙�
-    expressNumber: "", // 蹇�掑崟鍙�
   },
   form: {
     id: null,
-    salesContractNo: "",
     customerName: "",
     specificationModel: "",
     productName: "",
-    type: "璐ц溅", // 璐ц溅, 蹇��
     shippingDate: "",
     shippingCarNumber: "",
-    expressCompany: "",
-    expressNumber: "", // 蹇�掑崟鍙�
   },
   rules: {
-    salesContractNo: [
-      { required: true, message: "璇烽�夋嫨閿�鍞鍗�", trigger: "change" },
-    ],
     customerName: [
       { required: true, message: "璇疯緭鍏ュ鎴峰悕绉�", trigger: "blur" },
     ],
-    type: [{ 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",
-      },
+      { required: true, message: "璇疯緭鍏ュ彂璐ц溅鐗屽彿", trigger: "blur" },
     ],
   },
 });
@@ -444,19 +431,14 @@
     });
 };
 
-// 閿�鍞鍗曞彉鍖栨椂鑷姩濉厖瀹㈡埛鍚嶇О
-const handleSalesOrderChange = (value) => {
-  const selectedOrder = salesOrderOptions.value.find(
-    (item) => item.salesContractNo === value
-  );
-  if (selectedOrder) {
-    form.value.customerName = selectedOrder.customerName;
-  }
-};
+// 娌瑰搧鍑哄簱琛屾潵鑷� stock_out_record锛宨d 涓� shipping_info 浼氭挒鍙凤紝
+// 鍙戣揣/鍒犻櫎/璇︽儏绛夋帴鍙h儗鍚庨兘鏄� shipping_info锛屼笉鑳界敤浜庤繖绫昏
+const isOilOutRow = (row) => row?.source === "oilOut";
+const isRowSelectable = (row) => !isOilOutRow(row);
 
 // 琛ㄦ牸閫夋嫨鏁版嵁
 const handleSelectionChange = (selection) => {
-  selectedRows.value = selection;
+  selectedRows.value = selection.filter((item) => !isOilOutRow(item));
 };
 
 // 鎵撳紑寮规
@@ -472,13 +454,9 @@
   if (type === "edit" && row) {
     form.value = {
       id: row.id ?? null,
-      salesContractNo: row.salesContractNo ?? "",
       customerName: row.customerName ?? "",
-      type: row.type || "璐ц溅",
       shippingDate: row.shippingDate || getCurrentDate(),
       shippingCarNumber: row.shippingCarNumber ?? "",
-      expressCompany: row.expressCompany ?? "",
-      expressNumber: row.expressNumber ?? "",
     };
     deliveryFileList.value = row.storageBlobVOs || [];
   }
@@ -491,7 +469,8 @@
   detailRow.value = row || null;
   detailProductList.value = [];
   detailDialogVisible.value = true;
-  if (!row?.id) return;
+  // 娌瑰搧鍑哄簱琛屼笉璧板彂璐у崟璇︽儏鎺ュ彛锛坕d 浼氭挒鍙凤級锛岀洿鎺ョ敤鍒楄〃琛屾暟鎹睍绀�
+  if (!row?.id || isOilOutRow(row)) return;
   try {
     const res = await getDeliveryDetail(row.id);
     const detailData = res?.data;
@@ -554,7 +533,9 @@
     productName: item.productName ?? row.productName ?? "--",
     specificationModel:
       item.specificationModel ?? item.model ?? row.specificationModel ?? "--",
-    deliveryQuantity:
+    totalQuantity:
+      item.totalQuantity ??
+      row.totalQuantity ??
       item.deliveryQuantity ??
       item.quantity ??
       item.shippingQuantity ??
@@ -582,14 +563,8 @@
     if (valid) {
       const payload = {
         id: form.value.id,
-        type: form.value.type,
         shippingDate: form.value.shippingDate,
-        shippingCarNumber:
-          form.value.type === "璐ц溅" ? form.value.shippingCarNumber : "",
-        expressCompany:
-          form.value.type === "蹇��" ? form.value.expressCompany : "",
-        expressNumber:
-          form.value.type === "蹇��" ? form.value.expressNumber : "",
+        shippingCarNumber: form.value.shippingCarNumber,
         storageBlobDTOs: deliveryFileList.value || [],
       };
       deductStock(payload).then((res) => {
@@ -680,20 +655,6 @@
     });
 };
 
-// 鍙戣揣绫诲瀷鏍¢獙锛氳揣杞︽椂瑕佹眰杞︾墝锛屽揩閫掓椂瑕佹眰蹇�掑叕鍙�
-const validateShippingCarNumber = (value, callback) => {
-  if (form.value.type === "璐ц溅") {
-    if (!value) return callback(new Error("璇疯緭鍏ュ彂璐ц溅鐗屽彿"));
-  }
-  callback();
-};
-const validateExpressCompany = (value, callback) => {
-  if (form.value.type === "蹇��") {
-    if (!value) return callback(new Error("璇疯緭鍏ュ揩閫掑叕鍙�"));
-  }
-  callback();
-};
-
 // 鍙戣揣鍥剧墖涓婁紶鍓嶆牎妫�
 function handleDeliveryBeforeUpload(file) {
   // 鏍℃鏂囦欢绫诲瀷
@@ -764,16 +725,6 @@
     }
   }
 }
-
-// 鍙戣揣绫诲瀷鍒囨崲鏃舵竻绌哄搴斿瓧娈�
-const handleShippingTypeChange = (val) => {
-  if (val === "璐ц溅") {
-    form.value.expressCompany = "";
-    form.value.expressNumber = "";
-  } else {
-    form.value.shippingCarNumber = "";
-  }
-};
 
 // 鑾峰彇瀹℃牳鐘舵�佹枃鏈�
 const getApprovalStatusText = (status) => {
diff --git a/src/views/salesManagement/receiptPaymentLedger/index.vue b/src/views/salesManagement/receiptPaymentLedger/index.vue
index c5e3415..e8aecbc 100644
--- a/src/views/salesManagement/receiptPaymentLedger/index.vue
+++ b/src/views/salesManagement/receiptPaymentLedger/index.vue
@@ -42,12 +42,7 @@
                              :formatter="formattedNumber"
                              width="200" />
             <el-table-column label="鍥炴閲戦(鍏�)"
-                             prop="receiptPaymentAmount"
-                             show-overflow-tooltip
-                             :formatter="formattedNumber"
-                             width="200" />
-            <el-table-column label="閫�璐ч噾棰�(鍏�)"
-                             prop="returnAmount"
+                             prop="receiptRecordAmount"
                              show-overflow-tooltip
                              :formatter="formattedNumber"
                              width="200" />
@@ -59,6 +54,16 @@
                 <el-text type="danger">
                   {{ formattedNumber(row, column, row.receiptableAmount) }}
                 </el-text>
+              </template>
+            </el-table-column>
+            <el-table-column label="鎿嶄綔"
+                             align="center"
+                             width="90"
+                             fixed="right">
+              <template #default="{ row }">
+                <el-button link
+                           type="primary"
+                           @click.stop="openRecordDialog(row)">娴佹按</el-button>
               </template>
             </el-table-column>
           </el-table>
@@ -97,12 +102,7 @@
                              :formatter="formattedNumber"
                              width="200" />
             <el-table-column label="鍥炴閲戦(鍏�)"
-                             prop="receiptPaymentAmount"
-                             show-overflow-tooltip
-                             :formatter="formattedNumber"
-                             width="200" />
-            <el-table-column label="閫�璐ч噾棰�(鍏�)"
-                             prop="returnAmount"
+                             prop="receiptRecordAmount"
                              show-overflow-tooltip
                              :formatter="formattedNumber"
                              width="200" />
@@ -126,6 +126,14 @@
         </div>
       </el-col>
     </el-row>
+    <!-- 瀹㈡埛浠樻娴佹按缁存姢 -->
+    <PaymentRecordDialog v-model:visible="recordDialogVisible"
+                         title="瀹㈡埛浠樻娴佹按"
+                         :party-type="1"
+                         :party-id="recordPartyId"
+                         :party-name="recordPartyName"
+                         :direction="1"
+                         @changed="getList" />
   </div>
 </template>
 
@@ -136,6 +144,7 @@
     customewTransactionsDetails,
   } from "@/api/salesManagement/indicatorStats.js";
   import Pagination from "../../../components/PIMTable/Pagination.vue";
+  import PaymentRecordDialog from "@/components/PaymentRecordDialog/index.vue";
   const { proxy } = getCurrentInstance();
   const tableData = ref([]);
   const receiptRecord = ref([]);
@@ -159,6 +168,16 @@
   const customerId = ref("");
   const { searchForm } = toRefs(data);
   const originReceiptRecord = ref([]);
+  // 浠樻娴佹按寮圭獥
+  const recordDialogVisible = ref(false);
+  const recordPartyId = ref("");
+  const recordPartyName = ref("");
+
+  const openRecordDialog = row => {
+    recordPartyId.value = row.customerId;
+    recordPartyName.value = row.customerName || "";
+    recordDialogVisible.value = true;
+  };
   // 鏌ヨ鍒楄〃
   /** 鎼滅储鎸夐挳鎿嶄綔 */
   const handleQuery = () => {
@@ -190,12 +209,7 @@
   const summarizeMainTable = param => {
     return proxy.summarizeTable(
       param,
-      [
-        "contractAmounts",
-        "receiptPaymentAmount",
-        "returnAmount",
-        "receiptableAmount",
-      ],
+      ["contractAmounts", "receiptPaymentAmount", "receiptableAmount"],
       {
         ticketsNum: { noDecimal: true }, // 涓嶄繚鐣欏皬鏁�
         futureTickets: { noDecimal: true }, // 涓嶄繚鐣欏皬鏁�
@@ -206,12 +220,7 @@
   const summarizeMainTable1 = param => {
     var summarizeTable = proxy.summarizeTable(
       param,
-      [
-        "contractAmount",
-        "receiptPaymentAmount",
-        "returnAmount",
-        "receiptableAmount",
-      ],
+      ["contractAmount", "receiptPaymentAmount", "receiptableAmount"],
       {
         ticketsNum: { noDecimal: true }, // 涓嶄繚鐣欏皬鏁�
         futureTickets: { noDecimal: true }, // 涓嶄繚鐣欏皬鏁�
diff --git a/src/views/salesManagement/salesLedger/index.vue b/src/views/salesManagement/salesLedger/index.vue
index d2e82b5..c7d4c54 100644
--- a/src/views/salesManagement/salesLedger/index.vue
+++ b/src/views/salesManagement/salesLedger/index.vue
@@ -40,11 +40,32 @@
             @change="changeDaterange"
           />
         </el-form-item>
+        <el-form-item label="瀹℃壒鐘舵�侊細">
+          <el-select
+            v-model="searchForm.approvalStatus"
+            placeholder="璇烽�夋嫨"
+            clearable
+            style="width: 160px"
+            @change="handleQuery"
+          >
+            <el-option
+              v-for="item in approvalStatusOptions"
+              :key="item"
+              :label="item"
+              :value="item"
+            />
+          </el-select>
+        </el-form-item>
         <el-form-item>
           <el-button type="primary" @click="handleQuery"> 鎼滅储 </el-button>
         </el-form-item>
       </el-form>
     </div>
+    <!-- 鍗栨补 / 浠e偍鎷嗘垚涓や釜椤电锛屽悇鑷浐瀹氬甫 ledgerType 璋冨悓涓�涓垪琛ㄦ帴鍙� -->
+    <el-tabs v-model="activeTab" @tab-change="handleTabChange" class="ledger-tabs">
+      <el-tab-pane label="閿�鍞彴璐︼紙鍗栨补锛�" name="鍗栨补" />
+      <el-tab-pane label="浠e偍鍙拌处" name="浠e偍" />
+    </el-tabs>
     <div class="table_list">
       <div class="actions">
         <div></div>
@@ -72,7 +93,7 @@
         style="width: 100%"
         :summary-method="summarizeMainTable"
         @expand-change="expandChange"
-        height="calc(100vh - 18.5em)"
+        height="calc(100vh - 21.5em)"
       >
         <el-table-column
           align="center"
@@ -221,9 +242,22 @@
           label="鍚堝悓閲戦(鍏�)"
           prop="contractAmount"
           width="220"
-          show-overflow-tooltip
-          :formatter="formattedNumber"
-        />
+        >
+          <template #default="{ row, column }">
+            <el-tooltip
+              v-if="row.exceedsTrustFund"
+              :content="`鍚堝悓閲戦宸茶秴鍑鸿瀹㈡埛淇℃墭鍩洪噾锛堜俊鎵樺熀閲戯細${row.trustFund}锛塦"
+              placement="top"
+            >
+              <el-text type="danger">
+                {{ formattedNumber(row, column, row.contractAmount) }}
+              </el-text>
+            </el-tooltip>
+            <span v-else>
+              {{ formattedNumber(row, column, row.contractAmount) }}
+            </span>
+          </template>
+        </el-table-column>
         <el-table-column
           label="瀹為檯鍚堝悓閲戦(鍏�)"
           prop="netContractAmount"
@@ -255,6 +289,33 @@
           width="120"
           show-overflow-tooltip
         />
+        <el-table-column
+          label="閿�鍞被鍨�"
+          prop="ledgerType"
+          width="100"
+          show-overflow-tooltip
+        />
+        <el-table-column
+          v-if="activeTab === '浠e偍'"
+          label="娌瑰簱"
+          prop="oilDepotName"
+          width="180"
+          show-overflow-tooltip
+        />
+        <el-table-column
+          v-if="activeTab === '浠e偍'"
+          label="鍌ㄧ綈鍙�"
+          prop="tankNo"
+          width="140"
+          show-overflow-tooltip
+        />
+        <el-table-column label="瀹℃壒鐘舵��" width="110" align="center">
+          <template #default="{ row }">
+            <el-tag :type="getApprovalStatusType(row.approvalStatus)" size="small">
+              {{ row.approvalStatus || "-" }}
+            </el-tag>
+          </template>
+        </el-table-column>
         <el-table-column
           label="澶囨敞"
           prop="remarks"
@@ -314,8 +375,24 @@
         :rules="rules"
         ref="formRef"
       >
+        <el-row :gutter="30">
+          <el-col :span="12">
+            <el-form-item label="閿�鍞被鍨嬶細" prop="ledgerType">
+              <el-radio-group
+                v-model="form.ledgerType"
+                :disabled="operationType === 'view'"
+              >
+                <el-radio value="鍗栨补">鍗栨补</el-radio>
+                <el-radio value="浠e偍">鍗栧瓨鍌ㄤ綅缃紙浠e偍锛�</el-radio>
+              </el-radio-group>
+            </el-form-item>
+          </el-col>
+        </el-row>
         <!-- 鎶ヤ环鍗曞鍏ュ叆鍙o細鏀惧湪琛ㄥ崟椤堕儴锛岄�夋嫨鍚庡弽鏄惧鎴�/涓氬姟鍛樼瓑 -->
-        <el-row v-if="operationType === 'add'" style="margin-bottom: 10px">
+        <el-row
+          v-if="operationType === 'add' && form.ledgerType !== '浠e偍'"
+          style="margin-bottom: 10px"
+        >
           <el-col :span="24" style="text-align: right">
             <el-button type="primary" plain @click="openQuotationDialog">
               浠庨攢鍞姤浠峰鍏�
@@ -379,6 +456,7 @@
                 clearable
                 :disabled="operationType === 'view'"
                 filterable
+                @change="loadCustomerTrustFund"
               >
                 <el-option
                   v-for="item in customerOption"
@@ -483,7 +561,72 @@
             </el-form-item>
           </el-col>
         </el-row>
-        <el-row>
+        <!-- 浠e偍锛氬崠瀛樺偍浣嶇疆锛屽彧閫夋补搴�+鍌ㄧ綈骞舵墜宸ュ~鍚堝悓閲戦 -->
+        <el-row v-if="form.ledgerType === '浠e偍'" :gutter="30">
+          <el-col :span="12">
+            <el-form-item label="娌瑰簱锛�" prop="oilDepotId">
+              <el-select
+                v-model="form.oilDepotId"
+                placeholder="璇烽�夋嫨"
+                clearable
+                filterable
+                :disabled="operationType === 'view'"
+                style="width: 100%"
+              >
+                <el-option
+                  v-for="item in oilDepotOptions"
+                  :key="item.id"
+                  :label="item.depotName"
+                  :value="item.id"
+                />
+              </el-select>
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="鍌ㄧ綈鍙凤細" prop="tankId">
+              <el-select
+                v-model="form.tankId"
+                placeholder="璇烽�夋嫨"
+                clearable
+                filterable
+                :disabled="operationType === 'view'"
+                style="width: 100%"
+              >
+                <el-option
+                  v-for="item in tankOptions"
+                  :key="item.id"
+                  :label="item.tankNo"
+                  :value="item.id"
+                />
+              </el-select>
+            </el-form-item>
+          </el-col>
+        </el-row>
+        <el-row v-if="form.ledgerType === '浠e偍'" :gutter="30">
+          <el-col :span="12">
+            <el-form-item label="鍚堝悓閲戦(鍏�)锛�" prop="contractAmount">
+              <el-input-number
+                v-model="form.contractAmount"
+                :min="0"
+                :precision="2"
+                :controls="false"
+                placeholder="璇疯緭鍏�"
+                :disabled="operationType === 'view'"
+                style="width: 100%"
+              />
+              <!-- 閫変腑瀹㈡埛鍚庢湰鍦版瘮瀵逛俊鎵樺熀閲戯紝瀹炴椂棰勮鏄惁瓒呴檺 -->
+              <el-alert
+                v-if="isContractOverTrustFund"
+                type="warning"
+                show-icon
+                :closable="false"
+                class="trust-fund-alert"
+                :title="`鍚堝悓閲戦宸茶秴鍑鸿瀹㈡埛淇℃墭鍩洪噾锛堜俊鎵樺熀閲戯細${selectedCustomerTrustFund}锛塦"
+              />
+            </el-form-item>
+          </el-col>
+        </el-row>
+        <el-row v-if="form.ledgerType !== '浠e偍'">
           <el-form-item label="浜у搧淇℃伅锛�" prop="entryDate">
             <el-button
               v-if="operationType !== 'view'"
@@ -501,6 +644,7 @@
           </el-form-item>
         </el-row>
         <el-table
+          v-if="form.ledgerType !== '浠e偍'"
           :data="productData"
           border
           @selection-change="productSelected"
@@ -1172,7 +1316,7 @@
 <script setup>
 import { getToken } from "@/utils/auth";
 import pagination from "@/components/PIMTable/Pagination.vue";
-import { onMounted, ref, getCurrentInstance } from "vue";
+import { computed, onMounted, ref, getCurrentInstance } from "vue";
 import { addShippingInfo } from "@/api/salesManagement/deliveryLedger.js";
 import { ElMessageBox, ElMessage } from "element-plus";
 import useUserStore from "@/store/modules/user";
@@ -1198,7 +1342,9 @@
 import FileUpload from "@/components/AttachmentUpload/file/index.vue";
 import ImageUpload from "@/components/AttachmentUpload/image/index.vue";
 import { getCurrentDate } from "@/utils/index.js";
-import { listCustomer } from "@/api/basicData/customer.js";
+import { getCustomer, listCustomer } from "@/api/basicData/customer.js";
+import { allOilDepot } from "@/api/basicData/oilDepot.js";
+import { allTankInfo } from "@/api/basicData/tankInfo.js";
 
 const FileList = defineAsyncComponent(() =>
   import("@/components/Dialog/FileList.vue")
@@ -1209,6 +1355,14 @@
 const userStore = useUserStore();
 const { proxy } = getCurrentInstance();
 const { tax_rate } = proxy.useDict("tax_rate");
+// 鍗栨补 / 浠e偍涓や釜椤电锛屽浐瀹氬甫 ledgerType 璋冨悓涓�涓垪琛ㄦ帴鍙�
+const activeTab = ref("鍗栨补");
+const approvalStatusOptions = ["寰呭鎵�", "瀹℃牳涓�", "閫氳繃", "鎷掔粷"];
+// 浠e偍琛ㄥ崟锛氭补搴撱�佸偍缃愪笅鎷夛紙涓よ�呬簰鐩哥嫭绔嬶紝鍌ㄧ綈涓嶆寕鍦ㄦ补搴撲笅锛�
+const oilDepotOptions = ref([]);
+const tankOptions = ref([]);
+// 浠e偍琛ㄥ崟锛氶�変腑瀹㈡埛鐨勪俊鎵樺熀閲戯紝鐢ㄤ簬鍚堝悓閲戦瓒呴檺瀹炴椂棰勮
+const selectedCustomerTrustFund = ref(null);
 const tableData = ref([]);
 const productData = ref([]);
 const selectedRows = ref([]);
@@ -1236,6 +1390,7 @@
     entryDate: null, // 褰曞叆鏃ユ湡
     entryDateStart: undefined,
     entryDateEnd: undefined,
+    approvalStatus: "", // 瀹℃壒鐘舵��
   },
   form: {
     salesContractNo: "",
@@ -1250,8 +1405,13 @@
     executionDate: "",
     hasProductionRecord: false,
     createTime: "",
+    ledgerType: "鍗栨补", // 閿�鍞被鍨嬶細鍗栨补 / 浠e偍
+    oilDepotId: "", // 浠e偍锛氭补搴�
+    tankId: "", // 浠e偍锛氬偍缃�
+    contractAmount: null, // 浠e偍锛氬悎鍚岄噾棰濈敱鍓嶇鎵嬪伐濉�
   },
   rules: {
+    ledgerType: [{ required: true, message: "璇烽�夋嫨", trigger: "change" }],
     salesman: [{ required: true, message: "璇烽�夋嫨", trigger: "change" }],
     customerId: [{ required: true, message: "璇烽�夋嫨", trigger: "change" }],
     entryPerson: [{ required: true, message: "璇烽�夋嫨", trigger: "change" }],
@@ -1262,6 +1422,14 @@
 });
 const { form, rules } = toRefs(data);
 const { form: searchForm } = useFormData(data.searchForm);
+// 浠e偍鍚堝悓閲戦瓒呬俊鎵樺熀閲戯紙瀹㈡埛鏈淮鎶や俊鎵樺熀閲戞椂涓嶆彁绀猴級
+const isContractOverTrustFund = computed(() => {
+  const fund = selectedCustomerTrustFund.value;
+  if (fund === null || fund === undefined || fund === "") return false;
+  const amount = Number(form.value.contractAmount);
+  if (!(amount > 0)) return false;
+  return amount > Number(fund);
+});
 // 浜у搧琛ㄥ崟寮规鏁版嵁
 const productFormVisible = ref(false);
 const productOperationType = ref("");
@@ -1514,14 +1682,14 @@
 const getList = () => {
   tableLoading.value = true;
   const { entryDate, ...rest } = searchForm;
-  // 灏嗚寖鍥存棩鏈熷瓧娈典紶閫掔粰鍚庣
-  const params = { ...rest, ...page };
+  // 灏嗚寖鍥存棩鏈熷瓧娈典紶閫掔粰鍚庣锛沴edgerType 鐢卞綋鍓嶉〉绛惧喅瀹�
+  const params = { ...rest, ...page, ledgerType: activeTab.value };
   // 绉婚櫎褰曞叆鏃ユ湡鐨勯粯璁ゅ�艰缃紝鍙繚鐣欒寖鍥存棩鏈熷瓧娈�
   delete params.entryDate;
   return ledgerListPage(params)
     .then((res) => {
       tableLoading.value = false;
-      tableData.value = res.records;
+      tableData.value = res.records || [];
       tableData.value.map((item) => {
         item.children = [];
       });
@@ -1692,19 +1860,40 @@
 
 // 娣诲姞琛ㄨ绫诲悕鏂规硶
 const tableRowClassName = ({ row }) => {
-  if (!row.deliveryDate) return "";
-  if (row.isFh) return "";
-
-  const diff = row.deliveryDaysDiff;
-  if (diff === 15) {
-    return "yellow";
-  } else if (diff === 10) {
-    return "pink";
-  } else if (diff === 2) {
-    return "purple";
-  } else if (diff < 2) {
-    return "red";
+  let className = "";
+  if (row.deliveryDate && !row.isFh) {
+    const diff = row.deliveryDaysDiff;
+    if (diff === 15) {
+      className = "yellow";
+    } else if (diff === 10) {
+      className = "pink";
+    } else if (diff === 2) {
+      className = "purple";
+    } else if (diff < 2) {
+      className = "red";
+    }
   }
+  // 鏈瑪鍚堝悓閲戦瓒呭鎴蜂俊鎵樺熀閲戯細宸︿晶绾㈣竟锛屼笉瑕嗙洊涓婇潰鐨勪氦鏈熷簳鑹�
+  if (row.exceedsTrustFund) {
+    className = className ? `${className} trust-fund-exceed` : "trust-fund-exceed";
+  }
+  return className;
+};
+// 鍙拌处瀹℃壒鐘舵�侊紙鍚庣缁存姢锛屼笌鍙戣揣鐘舵�� statusTextMap 鏃犲叧锛�
+const getApprovalStatusType = status => {
+  const map = {
+    寰呭鎵�: "warning",
+    瀹℃牳涓�: "primary",
+    閫氳繃: "success",
+    鎷掔粷: "danger",
+  };
+  return map[status] || "info";
+};
+// 椤电鍒囨崲锛氭崲 ledgerType 閲嶆柊鏌ュ垪琛�
+const handleTabChange = () => {
+  page.current = 1;
+  expandedRowKeys.value = [];
+  getList();
 };
 // 涓昏〃鍚堣鏂规硶
 const summarizeMainTable = (param) => {
@@ -1750,14 +1939,24 @@
   form.value = {};
   productData.value = [];
   selectedQuotation.value = null;
+  selectedCustomerTrustFund.value = null;
   let userLists = await userListNoPage();
   userList.value = userLists.data;
   listCustomer({ current: -1, size: -1, type: 0 }).then((res) => {
     customerOption.value = res.data.records;
   });
+  // 娌瑰簱/鍌ㄧ綈涓嬫媺锛堜唬鍌ㄧ敤锛夛紝涓よ�呬簰鐩哥嫭绔�
+  allOilDepot().then((res) => {
+    oilDepotOptions.value = res.data || [];
+  });
+  allTankInfo().then((res) => {
+    tankOptions.value = res.data || [];
+  });
   form.value.entryPerson = userStore.id;
   if (type === "add") {
-    // 鏂板鏃惰缃綍鍏ユ棩鏈熶负褰撳ぉ
+    // 鏂板鏃堕粯璁よ窡闅忓綋鍓嶉〉绛剧殑閿�鍞被鍨�
+    form.value.ledgerType = activeTab.value;
+    // 褰曞叆鏃ユ湡榛樿涓哄綋澶�
     form.value.entryDate = getCurrentDate();
     // 绛捐鏃ユ湡榛樿涓哄綋澶�
     form.value.executionDate = getCurrentDate();
@@ -1770,10 +1969,15 @@
     getSalesLedgerWithProducts({ id: row.id, type: 1 }).then((res) => {
       form.value = { ...res };
       form.value.entryPerson = Number(res.entryPerson);
-      productData.value = form.value.productData;
+      // 鍘嗗彶鍗曟嵁/鍚庣鏈繑鍥炴椂鍏滃簳涓哄崠娌癸紝鍚﹀垯蹇呭~鏍¢獙浼氬崱浣忕紪杈�
+      form.value.ledgerType = form.value.ledgerType || "鍗栨补";
+      // 浠e偍娌℃湁浜у搧鏄庣粏
+      productData.value = form.value.productData || [];
       fileList.value = form.value.storageBlobVOs;
       // 缂栬緫鏃惰缃嚜鍔ㄧ敓鎴愪负false锛屽厑璁告墜鍔ㄤ慨鏀�
       form.value.autoGenerateContractNo = false;
+      // 鍥炴樉淇℃墭鍩洪噾锛屼緵浠e偍鍚堝悓閲戦瀹炴椂姣斿
+      loadCustomerTrustFund();
     });
   }
   // let userAll = await userStore.getInfo()
@@ -1784,6 +1988,18 @@
   // });
   form.value.entryDate = getCurrentDate(); // 璁剧疆榛樿褰曞叆鏃ユ湡涓哄綋鍓嶆棩鏈�
   dialogFormVisible.value = true;
+};
+
+// 鍙栬瀹㈡埛鐨勪俊鎵樺熀閲戯紝渚涗唬鍌ㄥ悎鍚岄噾棰濆疄鏃舵瘮瀵癸紙瀹㈡埛鏈淮鎶ゅ嵆涓虹┖锛屼笉鎻愮ず锛�
+const loadCustomerTrustFund = () => {
+  const id = form.value.customerId;
+  if (!id) {
+    selectedCustomerTrustFund.value = null;
+    return;
+  }
+  getCustomer(id).then((res) => {
+    selectedCustomerTrustFund.value = res?.data?.trustFund ?? null;
+  });
 };
 
 // 鎵撳紑鎶ヤ环鍗曢�夋嫨寮圭獥锛堜粎瀹℃壒閫氳繃锛�
@@ -1901,15 +2117,36 @@
 const submitForm = () => {
   proxy.$refs["formRef"].validate((valid) => {
     if (valid) {
-      console.log("productData.value--", productData.value);
-      if (productData.value !== null && productData.value.length > 0) {
-        form.value.productData = proxy.HaveJson(productData.value);
+      form.value.type = 1;
+      form.value.ledgerType = form.value.ledgerType || "鍗栨补";
+      if (form.value.ledgerType === "浠e偍") {
+        // 浠e偍锛氬崠瀛樺偍浣嶇疆锛屾病鏈変骇鍝佹槑缁嗭紝鍚堝悓閲戦鎵嬪伐濉�
+        if (!form.value.oilDepotId) {
+          proxy.$modal.msgWarning("浠e偍蹇呴』閫夋嫨娌瑰簱");
+          return;
+        }
+        if (!form.value.tankId) {
+          proxy.$modal.msgWarning("浠e偍蹇呴』閫夋嫨鍌ㄧ綈");
+          return;
+        }
+        if (!(Number(form.value.contractAmount) > 0)) {
+          proxy.$modal.msgWarning("浠e偍蹇呴』濉啓鍚堝悓閲戦");
+          return;
+        }
+        delete form.value.productData;
       } else {
-        proxy.$modal.msgWarning("璇锋坊鍔犱骇鍝佷俊鎭�");
-        return;
+        // 鍗栨补锛氬悎鍚岄噾棰濈敱浜у搧鏄庣粏姹囨�伙紝浠e偍瀛楁娓呯┖
+        if (productData.value !== null && productData.value.length > 0) {
+          form.value.productData = proxy.HaveJson(productData.value);
+        } else {
+          proxy.$modal.msgWarning("璇锋坊鍔犱骇鍝佷俊鎭�");
+          return;
+        }
+        form.value.oilDepotId = "";
+        form.value.tankId = "";
+        form.value.contractAmount = null;
       }
       form.value.storageBlobDTOs = fileList;
-      form.value.type = 1;
       if (form.value.autoGenerateContractNo) {
         form.value.salesContractNo = "";
       }
@@ -3024,6 +3261,28 @@
   background-color: #f4defa;
 }
 
+/* 鏈瑪鍚堝悓閲戦瓒呭鎴蜂俊鎵樺熀閲戯細鍙姞宸︿晶绾㈣竟锛岄伩鍏嶈鐩栦笂闈㈢殑浜ゆ湡搴曡壊 */
+:deep(.trust-fund-exceed) td:first-child {
+  box-shadow: inset 3px 0 0 var(--el-color-danger);
+}
+
+.trust-fund-alert {
+  margin-top: 6px;
+  width: 100%;
+}
+
+.ledger-tabs {
+  margin-bottom: 8px;
+}
+
+.ledger-tabs :deep(.el-tabs__header) {
+  margin-bottom: 0;
+}
+
+.ledger-tabs :deep(.el-tabs__content) {
+  display: none;
+}
+
 .table_list {
   margin-top: unset;
 }

--
Gitblit v1.9.3