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/salesManagement/salesLedger/index.vue |  321 ++++++++++++++++++++++++++++++++++++++++++++++++-----
 1 files changed, 290 insertions(+), 31 deletions(-)

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