From 7901e112887b40dda614a0ad3a412cf2e7f5ab3b Mon Sep 17 00:00:00 2001
From: gaoluyang <2820782392@qq.com>
Date: 星期三, 12 八月 2026 13:16:38 +0800
Subject: [PATCH] dev_天津_玮苓乐器 1.供应商往来添加付款功能 2.客户往来添加回款功能

---
 src/views/procurementManagement/paymentLedger/index.vue |  511 ++++++++++++++++++++++++++------------------------------
 1 files changed, 238 insertions(+), 273 deletions(-)

diff --git a/src/views/procurementManagement/paymentLedger/index.vue b/src/views/procurementManagement/paymentLedger/index.vue
index 741e6ac..08c3e0b 100644
--- a/src/views/procurementManagement/paymentLedger/index.vue
+++ b/src/views/procurementManagement/paymentLedger/index.vue
@@ -1,64 +1,54 @@
 <template>
   <div class="app-container">
-    <div class="search_form">
+    <div class="search_form"
+         style="margin-bottom: 20px;">
       <div>
         <span class="search_title">渚涘簲鍟嗗悕绉�:</span>
-        <el-input
-          v-model="searchForm.supplierName"
-          style="width: 240px"
-          placeholder="杈撳叆渚涘簲鍟嗗悕绉�"
-          @change="handleQuery"
-          clearable
-          :prefix-icon="Search"
-        />
-        <el-button type="primary" @click="handleQuery" style="margin-left: 10px"
-          >鎼滅储</el-button
-        >
+        <el-input v-model="searchForm.supplierName"
+                  style="width: 240px"
+                  placeholder="杈撳叆渚涘簲鍟嗗悕绉�"
+                  @change="handleQuery"
+                  clearable
+                  :prefix-icon="Search" />
+        <el-button type="primary"
+                   @click="handleQuery"
+                   style="margin-left: 10px">鎼滅储</el-button>
       </div>
       <div></div>
     </div>
     <el-row :gutter="20">
       <el-col :span="14">
         <div class="table_list">
-          <el-table
-            ref="multipleTable"
-            border
-            v-loading="tableLoading"
-            :data="tableData"
-            :header-cell-style="{ background: '#F0F1F5', color: '#333333' }"
-            height="calc(100vh - 18.5em)"
-            :highlight-current-row="true"
-            style="width: 100%"
-            tooltip-effect="dark"
-            @row-click="rowClick"
-            :show-summary="isShowSummary"
-            :summary-method="summarizeMainTable"
-            class="lims-table"
-          >
-            <el-table-column
-              align="center"
-              label="搴忓彿"
-              type="index"
-              width="60"
-            />
-            <el-table-column label="渚涘簲鍟嗗悕绉�" prop="supplierName" />
-            <el-table-column
-              label="鍙戠エ閲戦(鍏�)"
-              prop="invoiceAmount"
-              show-overflow-tooltip
-              :formatter="formattedNumber"
-            />
-            <el-table-column
-              label="浠樻閲戦(鍏�)"
-              prop="paymentAmount"
-              show-overflow-tooltip
-              :formatter="formattedNumber"
-            />
-            <el-table-column
-              label="搴斾粯閲戦(鍏�)"
-              prop="payableAmount"
-              show-overflow-tooltip
-            >
+          <el-table ref="multipleTable"
+                    border
+                    v-loading="tableLoading"
+                    :data="tableData"
+                    :header-cell-style="{ background: '#F0F1F5', color: '#333333' }"
+                    height="calc(100vh - 18.5em)"
+                    :highlight-current-row="true"
+                    style="width: 100%"
+                    tooltip-effect="dark"
+                    @row-click="rowClick"
+                    :show-summary="isShowSummary"
+                    :summary-method="summarizeMainTable"
+                    class="lims-table">
+            <el-table-column align="center"
+                             label="搴忓彿"
+                             type="index"
+                             width="60" />
+            <el-table-column label="渚涘簲鍟嗗悕绉�"
+                             prop="supplierName" />
+            <el-table-column label="鍚堝悓閲戦(鍏�)"
+                             prop="contractAmounts"
+                             show-overflow-tooltip
+                             :formatter="formattedNumber" />
+            <el-table-column label="浠樻閲戦(鍏�)"
+                             prop="paymentAmount"
+                             show-overflow-tooltip
+                             :formatter="formattedNumber" />
+            <el-table-column label="搴斾粯閲戦(鍏�)"
+                             prop="payableAmount"
+                             show-overflow-tooltip>
               <template #default="{ row, column }">
                 <el-text type="danger">
                   {{ formattedNumber(row, column, row.payableAmount) }}
@@ -66,250 +56,225 @@
               </template>
             </el-table-column>
           </el-table>
-          <pagination
-            v-show="total > 0"
-            @pagination="paginationSearch"
-            :total="total"
-            :layout="page.layout"
-            :page="page.current"
-            :limit="page.size"
-          />
+          <pagination v-show="total > 0"
+                      @pagination="paginationSearch"
+                      :total="total"
+                      :layout="page.layout"
+                      :page="page.current"
+                      :limit="page.size" />
         </div>
       </el-col>
       <el-col :span="10">
         <div class="table_list">
-          <PIMTable
-            rowKey="id"
-            :column="tableColumnSon"
-            :tableData="originalTableDataSon"
-            :isSelection="false"
-            :tableLoading="tableLoadingSon"
-            :isShowSummary="isShowSummarySon"
-            :summaryMethod="summarizeMainTable1"
-						height="calc(100vh - 18.5em)"
-          >
+          <PIMTable rowKey="id"
+                    :column="tableColumnSon"
+                    :tableData="originalTableDataSon"
+                    :isSelection="false"
+                    :isShowPagination="true"
+                    :page="sonPage"
+                    :tableLoading="tableLoadingSon"
+                    :isShowSummary="isShowSummarySon"
+                    :summaryMethod="summarizeMainTable1"
+                    height="calc(100vh - 18.5em)"
+                    @pagination="sonPaginationSearch">
             <template #payableAmountSlot="{ row }">
-              <el-text type="danger">
-                {{ parseFloat(row.payableAmount).toFixed(2) }}
-              </el-text>
+              <el-text type="danger">{{ parseFloat(row.payableAmount).toFixed(2) }}</el-text>
+            </template>
+            <template #paymentActionSlot="{ row }">
+              <el-button link type="primary" @click="openPaymentDialog(row)">鏂板浠樻</el-button>
             </template>
           </PIMTable>
-          <pagination
-            v-show="sonTotal > 0"
-            :total="sonTotal"
-            @pagination="sonPaginationSearch"
-            :layout="page.layout"
-            :page="sonPage.current"
-            :limit="sonPage.size"
-          />
         </div>
       </el-col>
     </el-row>
+
+    <el-dialog v-model="paymentDialogVisible" title="鏂板浠樻" width="35%" @close="closePaymentDialog">
+      <el-form :model="paymentForm" label-width="100px" :rules="paymentRules" ref="paymentFormRef">
+        <el-form-item label="閲囪喘鍚堝悓鍙凤細">{{ currentPaymentRow.purchaseContractNumber || '--' }}</el-form-item>
+        <el-form-item label="浠樻鏃ユ湡锛�" prop="paymentDate">
+          <el-date-picker style="width:100%" v-model="paymentForm.paymentDate" value-format="YYYY-MM-DD" type="date" placeholder="璇烽�夋嫨浠樻鏃ユ湡" clearable />
+        </el-form-item>
+        <el-form-item label="浠樻閲戦锛�" prop="paymentAmount">
+          <el-input-number style="width:100%" v-model="paymentForm.paymentAmount" :min="0" :max="Math.max(0,(Number(currentPaymentRow.payableAmount)||0)-(Number(currentPaymentRow.paymentAmount)||0))" placeholder="璇疯緭鍏ヤ粯娆鹃噾棰�" controls-position="right" />
+          <div style="color:#e6a23c;font-size:12px;margin-top:4px">褰撳墠鍙粯娆句綑棰濓細{{ Math.max(0,(Number(currentPaymentRow.payableAmount)||0)-(Number(currentPaymentRow.paymentAmount)||0)).toFixed(2) }} 鍏�</div>
+        </el-form-item>
+        <el-form-item label="浠樻鏂瑰紡锛�" prop="paymentMethod">
+          <el-select v-model="paymentForm.paymentMethod" placeholder="璇烽�夋嫨浠樻鏂瑰紡" style="width:100%" clearable>
+            <el-option label="閾惰杞处" value="閾惰杞处" /><el-option label="鐜伴噾" value="鐜伴噾" /><el-option label="鏀エ" value="鏀エ" /><el-option label="寰俊/鏀粯瀹�" value="寰俊/鏀粯瀹�" /><el-option label="鍏朵粬" value="鍏朵粬" />
+          </el-select>
+        </el-form-item>
+        <el-form-item label="澶囨敞锛�" prop="remark">
+          <el-input v-model="paymentForm.remark" type="textarea" :rows="3" placeholder="璇疯緭鍏ュ娉ㄤ俊鎭�" clearable />
+        </el-form-item>
+      </el-form>
+      <template #footer><el-button type="primary" @click="submitPaymentForm">纭</el-button><el-button @click="closePaymentDialog">鍙栨秷</el-button></template>
+    </el-dialog>
   </div>
 </template>
 
 <script setup>
-import { ref, toRefs } from "vue";
-import { Search } from "@element-plus/icons-vue";
-import {
-  paymentLedgerList,
-  paymentRecordList,
-} from "@/api/procurementManagement/paymentLedger.js";
-import Pagination from "../../../components/PIMTable/Pagination.vue";
+  import { ref, toRefs } from "vue";
+  import { Search } from "@element-plus/icons-vue";
+  import { paymentLedgerList, paymentRecordList, savePayment } from "@/api/procurementManagement/paymentLedger.js";
+  import Pagination from "../../../components/PIMTable/Pagination.vue";
 
-const tableColumn = ref([
-  {
-    label: "渚涘簲鍟嗗悕绉�",
-    prop: "supplierName",
-    width:240
-  },
-  {
-    label: "鍙戠エ閲戦(鍏�)",
-    prop: "invoiceAmount",
-  },
-  {
-    label: "浠樻閲戦(鍏�)",
-    prop: "paymentAmount",
-  },
-  {
-    label: "搴斾粯閲戦(鍏�)",
-    prop: "payableAmount",
-  },
-]);
-const tableData = ref([]);
-const tableLoading = ref(false);
-const data = reactive({
-  searchForm: {
-    supplierNameOrContractNo: "",
-  },
-});
-const page = reactive({
-  current: 1,
-  size: 100,
-});
-const sonPage = reactive({
-  current: 1,
-  size: 100,
-});
-const total = ref(0);
-const sonTotal = ref(0);
-const isShowSummary = ref(true);
-const { searchForm } = toRefs(data);
-const currentSupplierId = ref("");
-const rowClick = (row) => {
-  currentSupplierId.value = row.supplierId;
-  getPaymenRecordtList(row.supplierId);
-};
-// 瀛愭ā鍧�
-const tableColumnSon = ref([
-  {
-    label: "鍙戠敓鏃ユ湡",
-    prop: "happenTime",
-		width: 110,
-  },
-  {
-    label: "鍙戠エ閲戦(鍏�)",
-    prop: "invoiceAmount",
-		width: 200,
-    formatData: (params) => {
-      return params ? parseFloat(params).toFixed(2) : 0;
-    },
-  },
-  {
-    label: "浠樻閲戦(鍏�)",
-    prop: "currentPaymentAmount",
-		width: 200,
-    formatData: (params) => {
-      return params ? parseFloat(params).toFixed(2) : 0;
-    },
-  },
-  {
-    label: "搴斾粯閲戦(鍏�)",
-    dataType: "slot",
-		width: 200,
-    prop: "payableAmount",
-    slot: "payableAmountSlot",
-  },
-]);
-const tableDataSon = ref([]);
-const originalTableDataSon = ref([]);
-const tableLoadingSon = ref(false);
-const isShowSummarySon = ref(true);
-const detailPageNum = ref(1);
-const detailPageSize = ref(10);
-const { proxy } = getCurrentInstance();
+  const tableData = ref([]);
+  const tableLoading = ref(false);
+  const data = reactive({ searchForm: { supplierName: "" } });
+  const page = reactive({ current: 1, size: 100 });
+  const sonPage = reactive({ current: 1, size: 10, total: 0, layout: "total, sizes, prev, pager, next, jumper" });
+  const total = ref(0);
+  const isShowSummary = ref(true);
+  const { searchForm } = toRefs(data);
+  const currentSupplierId = ref("");
+  const rowClick = row => { currentSupplierId.value = row.supplierId; sonPage.current = 1; getPaymenRecordtList(row.supplierId); };
+  const tableColumnSon = ref([
+    { label:"鍚堝悓绛捐鏃ユ湡", prop:"executionDate", width:110 },
+    { label:"閲囪喘鍚堝悓鍙�", prop:"purchaseContractNumber", width:150 },
+    { label:"鍚堝悓閲戦(鍏�)", prop:"contractAmount", width:200, formatData: p => p ? parseFloat(p).toFixed(2) : 0 },
+    { label:"浠樻閲戦(鍏�)", prop:"paymentAmount", width:200, formatData: p => p ? parseFloat(p).toFixed(2) : 0 },
+    { label:"搴斾粯閲戦(鍏�)", dataType:"slot", width:200, prop:"payableAmount", slot:"payableAmountSlot" },
+    { label:"鎿嶄綔", dataType:"slot", slot:"paymentActionSlot", width:100, fixed:"right", align:"center" },
+  ]);
+  const tableDataSon = ref([]);
+  const originalTableDataSon = ref([]);
+  const tableLoadingSon = ref(false);
+  const isShowSummarySon = ref(true);
+  const { proxy } = getCurrentInstance();
 
-// 涓昏〃鍚堣鏂规硶
-const summarizeMainTable = (param) => {
-  return proxy.summarizeTable(
-    param,
-    ["invoiceAmount", "paymentAmount", "payableAmount"],
-    {
-      ticketsNum: { noDecimal: true }, // 涓嶄繚鐣欏皬鏁�
-      futureTickets: { noDecimal: true }, // 涓嶄繚鐣欏皬鏁�
-    }
-  );
-};
-// 瀛愯〃鍚堣鏂规硶
-const summarizeMainTable1 = (param) => {
-  let summarizeTable = proxy.summarizeTable(
-    param,
-    ["invoiceAmount", "currentPaymentAmount"],
-    {
-      ticketsNum: { noDecimal: true }, // 涓嶄繚鐣欏皬鏁�
-      futureTickets: { noDecimal: true }, // 涓嶄繚鐣欏皬鏁�
-    }
-  );
-  if (originalTableDataSon.value.length > 0) {
-    summarizeTable[summarizeTable.length - 1] =
-      originalTableDataSon.value[
-        originalTableDataSon.value.length - 1
-      ].payableAmount.toFixed(2);
-  } else {
-    summarizeTable[summarizeTable.length - 1] = 0.0;
-  }
-  return summarizeTable;
-};
-/** 鎼滅储鎸夐挳鎿嶄綔 */
-const handleQuery = () => {
-  page.current = 1;
-  getList();
-};
-const paginationSearch = (obj) => {
-  page.current = obj.page;
-  page.size = obj.limit;
-  getList();
-};
-const getList = () => {
-  tableLoading.value = true;
-  paymentLedgerList({
-    ...searchForm.value,
-    ...page,
-    detailPageNum: detailPageNum.value, // 鏂板
-    detailPageSize: detailPageSize.value, // 鏂板
-  }).then((res) => {
-    let result = res.data;
-    tableLoading.value = false;
-    tableData.value = result.records || [];
-    total.value = result.total || 0;
-    if (tableData.value.length > 0) {
-      getPaymenRecordtList(tableData.value[0].supplierId);
-      currentSupplierId.value = tableData.value[0].supplierId;
-    }
-  });
-};
+  const paymentDialogVisible = ref(false);
+  const currentPaymentRow = ref({});
+  const paymentFormRef = ref(null);
+  const paymentForm = reactive({ paymentDate:"", paymentAmount:undefined, paymentMethod:"", remark:"" });
+  const vPA = (_,v,cb) => { if(!v) return cb(new Error("璇疯緭鍏ヤ粯娆鹃噾棰�")); const m=Math.max(0,(Number(currentPaymentRow.value.payableAmount)||0)-(Number(currentPaymentRow.value.paymentAmount)||0)); if(v>m) return cb(new Error(`浠樻閲戦涓嶈兘瓒呰繃鍙粯娆句綑棰� ${m.toFixed(2)} 鍏僠)); cb(); };
+  const paymentRules = { paymentDate:[{required:true,message:"璇烽�夋嫨浠樻鏃ユ湡",trigger:"change"}], paymentAmount:[{required:true,validator:vPA,trigger:"blur"}], paymentMethod:[{required:true,message:"璇烽�夋嫨浠樻鏂瑰紡",trigger:"change"}] };
+  const openPaymentDialog = r => { currentPaymentRow.value=r; paymentForm.paymentDate=""; paymentForm.paymentAmount=undefined; paymentForm.paymentMethod=""; paymentForm.remark=""; paymentDialogVisible.value=true; };
+  const closePaymentDialog = () => { paymentFormRef.value?.resetFields(); paymentDialogVisible.value=false; };
+  const submitPaymentForm = () => { paymentFormRef.value?.validate(v=>{ if(v){ savePayment({ supplierId:currentSupplierId.value, purchaseContractNumber:currentPaymentRow.value.purchaseContractNumber, paymentDate:paymentForm.paymentDate, paymentAmount:paymentForm.paymentAmount, paymentMethod:paymentForm.paymentMethod, remark:paymentForm.remark }).then(res=>{ proxy.$modal.msgSuccess("鏂板浠樻鎴愬姛"); closePaymentDialog(); getPaymenRecordtList(currentSupplierId.value); getList(); }); } }); };
 
-const getPaymenRecordtList = (supplierId) => {
-  tableLoadingSon.value = true;
-  paymentRecordList(supplierId)
-    .then((res) => {
-      tableLoadingSon.value = false;
-      tableDataSon.value = res.data;
-      handlePagination({ page: 1, limit: sonPage.size });
-      sonTotal.value = res.data.length;
-    })
-    .catch((e) => {
-      tableLoadingSon.value = false;
+  // 涓昏〃鍚堣鏂规硶
+  const summarizeMainTable = param => {
+    return proxy.summarizeTable(
+      param,
+      ["contractAmounts", "paymentAmount", "payableAmount"],
+      {
+        ticketsNum: { noDecimal: true }, // 涓嶄繚鐣欏皬鏁�
+        futureTickets: { noDecimal: true }, // 涓嶄繚鐣欏皬鏁�
+      }
+    );
+  };
+  // 瀛愯〃鍚堣鏂规硶
+  const summarizeMainTable1 = param => {
+    let summarizeTable = proxy.summarizeTable(
+      param,
+      ["contractAmount", "invoiceAmount", "paymentAmount"],
+      {
+        ticketsNum: { noDecimal: true }, // 涓嶄繚鐣欏皬鏁�
+        futureTickets: { noDecimal: true }, // 涓嶄繚鐣欏皬鏁�
+      }
+    );
+    if (originalTableDataSon.value.length > 0) {
+      summarizeTable[summarizeTable.length - 1] =
+        originalTableDataSon.value[
+          originalTableDataSon.value.length - 1
+        ].payableAmount.toFixed(2);
+    } else {
+      summarizeTable[summarizeTable.length - 1] = 0.0;
+    }
+    return summarizeTable;
+  };
+  /** 鎼滅储鎸夐挳鎿嶄綔 */
+  const handleQuery = () => {
+    page.current = 1;
+    getList();
+  };
+  const paginationSearch = obj => {
+    page.current = obj.page;
+    page.size = obj.limit;
+    getList();
+  };
+  const getList = () => {
+    tableLoading.value = true;
+    paymentLedgerList({
+      ...searchForm.value,
+      ...page,
+    }).then(res => {
+      let result = res.data;
+      tableLoading.value = false;
+      tableData.value = result.records || [];
+      total.value = result.total || 0;
+      if (tableData.value.length > 0) {
+        currentSupplierId.value = tableData.value[0].supplierId;
+        sonPage.current = 1;
+        getPaymenRecordtList(tableData.value[0].supplierId);
+      }
     });
-};
-const handlePagination = ({ page, limit }) => {
-  sonPage.current = page;
-  sonPage.size = limit;
+  };
 
-  const start = (page - 1) * limit;
-  const end = start + limit;
+  const getPaymenRecordtList = supplierId => {
+    tableLoadingSon.value = true;
+    paymentRecordList({
+      supplierId: supplierId,
+      current: sonPage.current,
+      size: sonPage.size,
+    })
+      .then(res => {
+        tableLoadingSon.value = false;
+        let result = res.data;
+        if (Array.isArray(result)) {
+          tableDataSon.value = result;
+          sonPage.total = result.length;
+          handlePagination({ page: sonPage.current, limit: sonPage.size });
+        } else {
+          originalTableDataSon.value = result.records || [];
+          sonPage.total = result.total || 0;
+        }
+      })
+      .catch(e => {
+        tableLoadingSon.value = false;
+      });
+  };
+  const handlePagination = ({ page, limit }) => {
+    console.log(page, limit);
+    sonPage.current = page;
+    sonPage.size = limit;
 
-  originalTableDataSon.value = tableDataSon.value.slice(start, end);
-};
+    const start = (page - 1) * limit;
+    const end = start + limit;
 
-const sonPaginationSearch = (pagination) => {
-  // 鎺ユ敹鍒嗛〉鍣ㄥ弬鏁� { page, limit }
-  handlePagination(pagination);
-};
-const formattedNumber = (row, column, cellValue) => {
-  if (column.property !== "supplierName") {
-    return parseFloat(cellValue).toFixed(2);
-  } else {
-    return cellValue;
-  }
-};
-getList();
+    originalTableDataSon.value = tableDataSon.value.slice(start, end);
+  };
+
+  const sonPaginationSearch = pagination => {
+    // 鎺ユ敹鍒嗛〉鍣ㄥ弬鏁� { page, limit }
+    sonPage.current = pagination.page;
+    sonPage.size = pagination.limit;
+    getPaymenRecordtList(currentSupplierId.value);
+  };
+  const formattedNumber = (row, column, cellValue) => {
+    if (column.property !== "supplierName") {
+      return parseFloat(cellValue).toFixed(2);
+    } else {
+      return cellValue;
+    }
+  };
+  getList();
 </script>
 
 <style scoped lang="scss">
-.el-pagination {
-  width: 100%;
-  height: 55px;
-  display: flex;
-  justify-content: flex-end;
-  float: right;
-  flex-direction: row;
-  align-items: center;
-  background: #fff;
-  margin: -20px 0 0 0;
-  padding: 0 20px;
-}
-.pagination-container {
-  margin-top: 0;
-}
+  .el-pagination {
+    width: 100%;
+    height: 55px;
+    display: flex;
+    justify-content: flex-end;
+    float: right;
+    flex-direction: row;
+    align-items: center;
+    background: #fff;
+    margin: -20px 0 0 0;
+    padding: 0 20px;
+  }
+  .pagination-container {
+    margin-top: 0;
+  }
 </style>

--
Gitblit v1.9.3