From 1ffe9b9bf12e1670fbfae0b9acbec95d4aaebe16 Mon Sep 17 00:00:00 2001
From: spring <2396852758@qq.com>
Date: 星期三, 20 五月 2026 16:23:23 +0800
Subject: [PATCH] fix: 完成财务模块接口对接

---
 src/api/financialManagement/accountPurchasePayment.js       |   32 
 src/api/financialManagement/accountPurchaseInvoice.js       |   50 
 src/views/financialManagement/payable/payment.vue           |  410 +--
 src/views/financialManagement/receivable/receipt.vue        |  678 +++++-
 src/views/financialManagement/receivable/invoiceApply.vue   |  239 ++
 src/api/financialManagement/accountPaymentApplication.js    |   59 
 src/api/financialManagement/accountSalesInvoice.js          |   41 
 src/views/financialManagement/payable/input-invoice.vue     |  918 ++++++++--
 src/views/financialManagement/payable/paymentApply.vue      |  970 +++++++++-
 src/views/financialManagement/payable/reconciliation.vue    |  613 +++++-
 src/api/financialManagement/accountStatement.js             |   41 
 src/views/financialManagement/payable/purchaseIn.vue        |   50 
 src/api/financialManagement/accountSalesCollection.js       |   50 
 src/views/financialManagement/receivable/reconciliation.vue |  563 ++++-
 src/views/financialManagement/receivable/outputInvoice.vue  |  489 ++++-
 src/views/financialManagement/payable/purchaseReturn.vue    |  113 
 16 files changed, 3,997 insertions(+), 1,319 deletions(-)

diff --git a/src/api/financialManagement/accountPaymentApplication.js b/src/api/financialManagement/accountPaymentApplication.js
new file mode 100644
index 0000000..0d5e438
--- /dev/null
+++ b/src/api/financialManagement/accountPaymentApplication.js
@@ -0,0 +1,59 @@
+import request from "@/utils/request";
+
+/** 鏍规嵁渚涘簲鍟嗘煡璇㈠彲鍏宠仈鍏ュ簱鍗� */
+export function getInboundBatchesBySupplier(params) {
+  return request({
+    url: "/accountPaymentApplication/getInboundBatchesBySupplier",
+    method: "get",
+    params,
+  });
+}
+
+/** 鏂板浠樻鐢宠 */
+export function addAccountPaymentApplication(data) {
+  return request({
+    url: "/accountPaymentApplication/addAccountPaymentApplication",
+    method: "post",
+    data,
+  });
+}
+
+/** 浠樻鐢宠鍒嗛〉鍒楄〃 */
+export function listPageAccountPaymentApplication(params) {
+  return request({
+    url: "/accountPaymentApplication/listPageAccountPaymentApplication",
+    method: "get",
+    params,
+  });
+}
+
+/** 淇敼浠樻鐢宠 */
+export function updateAccountPaymentApplication(data) {
+  return request({
+    url: "/accountPaymentApplication/updateAccountPaymentApplication",
+    method: "put",
+    data,
+  });
+}
+
+/** 瀹℃牳浠樻鐢宠 */
+export function auditAccountPaymentApplication(data) {
+  return request({
+    url: "/accountPaymentApplication/auditAccountPaymentApplication",
+    method: "put",
+    data,
+  });
+}
+
+/** 鍒犻櫎浠樻鐢宠锛圫pring 瑕佹眰 ids=1&ids=2 鏌ヨ鍙傛暟锛� */
+export function deleteAccountPaymentApplication(ids) {
+  const idList = Array.isArray(ids) ? ids : [ids];
+  const query = idList
+    .filter((id) => id !== undefined && id !== null && id !== "")
+    .map((id) => `ids=${encodeURIComponent(id)}`)
+    .join("&");
+  return request({
+    url: `/accountPaymentApplication/deleteAccountPaymentApplication?${query}`,
+    method: "delete",
+  });
+}
diff --git a/src/api/financialManagement/accountPurchaseInvoice.js b/src/api/financialManagement/accountPurchaseInvoice.js
new file mode 100644
index 0000000..af391da
--- /dev/null
+++ b/src/api/financialManagement/accountPurchaseInvoice.js
@@ -0,0 +1,50 @@
+import request from "@/utils/request";
+
+/** 鏍规嵁渚涘簲鍟嗘煡璇㈠彲鍏宠仈鍏ュ簱鍗� */
+export function getInboundBatchesBySupplier(params) {
+  return request({
+    url: "/accountPurchaseInvoice/getInboundBatchesBySupplier",
+    method: "get",
+    params,
+  });
+}
+
+/** 鏂板杩涢」鍙戠エ */
+export function addAccountPurchaseInvoice(data) {
+  return request({
+    url: "/accountPurchaseInvoice/addAccountPurchaseInvoice",
+    method: "post",
+    data,
+  });
+}
+
+/** 杩涢」鍙戠エ鍒嗛〉鍒楄〃 */
+export function listPageAccountPurchaseInvoice(params) {
+  return request({
+    url: "/accountPurchaseInvoice/listPageAccountPurchaseInvoice",
+    method: "get",
+    params,
+  });
+}
+
+/** 浣滃簾杩涢」鍙戠エ */
+export function cancelAccountPurchaseInvoice(data) {
+  return request({
+    url: "/accountPurchaseInvoice/cancelAccountPurchaseInvoice",
+    method: "put",
+    data,
+  });
+}
+
+/** 鍒犻櫎杩涢」鍙戠エ锛圫pring 瑕佹眰 ids=1&ids=2 鏌ヨ鍙傛暟锛� */
+export function deleteAccountPurchaseInvoice(ids) {
+  const idList = Array.isArray(ids) ? ids : [ids];
+  const query = idList
+    .filter((id) => id !== undefined && id !== null && id !== "")
+    .map((id) => `ids=${encodeURIComponent(id)}`)
+    .join("&");
+  return request({
+    url: `/accountPurchaseInvoice/deleteAccountPurchaseInvoice?${query}`,
+    method: "delete",
+  });
+}
diff --git a/src/api/financialManagement/accountPurchasePayment.js b/src/api/financialManagement/accountPurchasePayment.js
new file mode 100644
index 0000000..a10f05a
--- /dev/null
+++ b/src/api/financialManagement/accountPurchasePayment.js
@@ -0,0 +1,32 @@
+import request from "@/utils/request";
+
+/** 鏂板浠樻鍗曪紙鍏宠仈浠樻鐢宠锛� */
+export function addAccountPurchasePayment(data) {
+  return request({
+    url: "/accountPurchasePayment/addAccountPurchasePayment",
+    method: "post",
+    data,
+  });
+}
+
+/** 浠樻鍗曞垎椤靛垪琛� */
+export function listPageAccountPurchasePayment(params) {
+  return request({
+    url: "/accountPurchasePayment/listPageAccountPurchasePayment",
+    method: "get",
+    params,
+  });
+}
+
+/** 鍒犻櫎浠樻鍗曪紙Spring 瑕佹眰 ids=1&ids=2 鏌ヨ鍙傛暟锛� */
+export function deleteAccountPurchasePayment(ids) {
+  const idList = Array.isArray(ids) ? ids : [ids];
+  const query = idList
+    .filter((id) => id !== undefined && id !== null && id !== "")
+    .map((id) => `ids=${encodeURIComponent(id)}`)
+    .join("&");
+  return request({
+    url: `/accountPurchasePayment/deleteAccountPurchasePayment?${query}`,
+    method: "delete",
+  });
+}
diff --git a/src/api/financialManagement/accountSalesCollection.js b/src/api/financialManagement/accountSalesCollection.js
new file mode 100644
index 0000000..abeb977
--- /dev/null
+++ b/src/api/financialManagement/accountSalesCollection.js
@@ -0,0 +1,50 @@
+import request from "@/utils/request";
+
+/** 鏍规嵁瀹㈡埛鏌ヨ鍙叧鑱斿嚭搴撳崟 */
+export function getOutboundBatchesByCustomer(params) {
+  return request({
+    url: "/accountSalesCollection/getOutboundBatchesByCustomer",
+    method: "get",
+    params,
+  });
+}
+
+/** 鏂板鏀舵鍗� */
+export function addAccountSalesCollection(data) {
+  return request({
+    url: "/accountSalesCollection/addAccountSalesCollection",
+    method: "post",
+    data,
+  });
+}
+
+/** 鏀舵鍗曞垎椤靛垪琛� */
+export function listPageAccountSalesCollection(params) {
+  return request({
+    url: "/accountSalesCollection/listPageAccountSalesCollection",
+    method: "get",
+    params,
+  });
+}
+
+/** 淇敼鏀舵鍗� */
+export function updateAccountSalesCollection(data) {
+  return request({
+    url: "/accountSalesCollection/updateAccountSalesCollection",
+    method: "put",
+    data,
+  });
+}
+
+/** 鍒犻櫎鏀舵鍗曪紙Spring 瑕佹眰 ids=1&ids=2 鏌ヨ鍙傛暟锛� */
+export function deleteAccountSalesCollection(ids) {
+  const idList = Array.isArray(ids) ? ids : [ids];
+  const query = idList
+    .filter((id) => id !== undefined && id !== null && id !== "")
+    .map((id) => `ids=${encodeURIComponent(id)}`)
+    .join("&");
+  return request({
+    url: `/accountSalesCollection/deleteAccountSalesCollection?${query}`,
+    method: "delete",
+  });
+}
diff --git a/src/api/financialManagement/accountSalesInvoice.js b/src/api/financialManagement/accountSalesInvoice.js
new file mode 100644
index 0000000..6e74c53
--- /dev/null
+++ b/src/api/financialManagement/accountSalesInvoice.js
@@ -0,0 +1,41 @@
+import request from "@/utils/request";
+
+/** 鏂板閿�椤瑰彂绁� */
+export function addAccountSalesInvoice(data) {
+  return request({
+    url: "/accountSalesInvoice/addAccountSalesInvoice",
+    method: "post",
+    data,
+  });
+}
+
+/** 閿�椤瑰彂绁ㄥ垎椤靛垪琛� */
+export function listPageAccountSalesInvoice(params) {
+  return request({
+    url: "/accountSalesInvoice/listPageAccountSalesInvoice",
+    method: "get",
+    params,
+  });
+}
+
+/** 浣滃簾閿�椤瑰彂绁� */
+export function cancelAccountSalesInvoice(data) {
+  return request({
+    url: "/accountSalesInvoice/cancelAccountSalesInvoice",
+    method: "put",
+    data,
+  });
+}
+
+/** 鍒犻櫎閿�椤瑰彂绁紙Spring 瑕佹眰 ids=1&ids=2 鏌ヨ鍙傛暟锛� */
+export function deleteAccountSalesInvoice(ids) {
+  const idList = Array.isArray(ids) ? ids : [ids];
+  const query = idList
+    .filter((id) => id !== undefined && id !== null && id !== "")
+    .map((id) => `ids=${encodeURIComponent(id)}`)
+    .join("&");
+  return request({
+    url: `/accountSalesInvoice/deleteAccountSalesInvoice?${query}`,
+    method: "delete",
+  });
+}
diff --git a/src/api/financialManagement/accountStatement.js b/src/api/financialManagement/accountStatement.js
new file mode 100644
index 0000000..bf80101
--- /dev/null
+++ b/src/api/financialManagement/accountStatement.js
@@ -0,0 +1,41 @@
+import request from "@/utils/request";
+
+/** 鎸夋湀浠芥煡璇㈠璐﹀崟鏄庣粏锛堢敓鎴愬墠棰勮锛� */
+export function getAccountStatementDetailsByMonth(params) {
+  return request({
+    url: "/accountStatement/getAccountStatementDetailsByMonth",
+    method: "get",
+    params,
+  });
+}
+
+/** 鏂板瀵硅处鍗� */
+export function addAccountStatement(data) {
+  return request({
+    url: "/accountStatement/addAccountStatement",
+    method: "post",
+    data,
+  });
+}
+
+/** 瀵硅处鍗曞垎椤靛垪琛� */
+export function listPageAccountStatement(params) {
+  return request({
+    url: "/accountStatement/listPageAccountStatement",
+    method: "get",
+    params,
+  });
+}
+
+/** 鍒犻櫎瀵硅处鍗曪紙Spring 瑕佹眰 ids=1&ids=2 鏌ヨ鍙傛暟锛� */
+export function deleteAccountStatement(ids) {
+  const idList = Array.isArray(ids) ? ids : [ids];
+  const query = idList
+    .filter((id) => id !== undefined && id !== null && id !== "")
+    .map((id) => `ids=${encodeURIComponent(id)}`)
+    .join("&");
+  return request({
+    url: `/accountStatement/deleteAccountStatement?${query}`,
+    method: "delete",
+  });
+}
diff --git a/src/views/financialManagement/payable/input-invoice.vue b/src/views/financialManagement/payable/input-invoice.vue
index 660d0dd..86ebd09 100644
--- a/src/views/financialManagement/payable/input-invoice.vue
+++ b/src/views/financialManagement/payable/input-invoice.vue
@@ -1,50 +1,61 @@
 <template>
   <div class="app-container">
     <el-form :model="filters" :inline="true">
-      <el-form-item label="鍙戠エ浠g爜:">
-        <el-input v-model="filters.invoiceCode" placeholder="璇疯緭鍏ュ彂绁ㄤ唬鐮�" clearable style="width: 200px;" />
-      </el-form-item>
       <el-form-item label="鍙戠エ鍙风爜:">
-        <el-input v-model="filters.invoiceNo" placeholder="璇疯緭鍏ュ彂绁ㄥ彿鐮�" clearable style="width: 200px;" />
+        <el-input v-model="filters.invoiceNumber" placeholder="璇疯緭鍏ュ彂绁ㄥ彿鐮�" clearable style="width: 200px;" />
       </el-form-item>
       <el-form-item label="渚涘簲鍟�:">
-        <el-select v-model="filters.supplierId" placeholder="璇烽�夋嫨渚涘簲鍟�" clearable style="width: 200px;">
-          <el-option v-for="item in supplierList" :key="item.id" :label="item.name" :value="item.id" />
+        <el-select v-model="filters.supplierId" placeholder="璇烽�夋嫨渚涘簲鍟�" clearable filterable style="width: 200px;">
+          <el-option
+            v-for="item in supplierList"
+            :key="item.id"
+            :label="item.supplierName"
+            :value="item.id"
+          />
         </el-select>
       </el-form-item>
-      <el-form-item label="璁よ瘉鐘舵��:">
-        <el-select v-model="filters.certifyStatus" placeholder="璇烽�夋嫨璁よ瘉鐘舵��" clearable style="width: 150px;">
-          <el-option label="鏈璇�" value="uncertified" />
-          <el-option label="宸茶璇�" value="certified" />
-          <el-option label="璁よ瘉澶辫触" value="failed" />
+      <el-form-item label="寮�绁ㄦ棩鏈�:">
+        <el-date-picker
+          v-model="filters.dateRange"
+          type="daterange"
+          value-format="YYYY-MM-DD"
+          format="YYYY-MM-DD"
+          range-separator="鑷�"
+          start-placeholder="寮�濮嬫棩鏈�"
+          end-placeholder="缁撴潫鏃ユ湡"
+          clearable
+          style="width: 240px;"
+        />
+      </el-form-item>
+      <el-form-item label="鐘舵��:">
+        <el-select v-model="filters.status" placeholder="璇烽�夋嫨鐘舵��" clearable style="width: 150px;">
+          <el-option label="姝e父" :value="0" />
+          <el-option label="浣滃簾" :value="1" />
         </el-select>
       </el-form-item>
       <el-form-item>
-        <el-button type="primary" @click="getTableData">鎼滅储</el-button>
+        <el-button type="primary" @click="onSearch">鎼滅储</el-button>
         <el-button @click="resetFilters">閲嶇疆</el-button>
       </el-form-item>
     </el-form>
     <div class="table_list">
       <div class="actions">
-        <div>
-          <el-button type="success" @click="handleBatchCertify" icon="Check" :disabled="selectedRows.length === 0">鎵归噺璁よ瘉</el-button>
-        </div>
+        <div></div>
         <div>
           <el-button type="primary" @click="add" icon="Plus">褰曞叆鍙戠エ</el-button>
-          <el-button @click="handleOut" icon="Download">瀵煎嚭</el-button>
+          <el-button @click="handleExport" icon="Download">瀵煎嚭</el-button>
         </div>
       </div>
       <PIMTable
         rowKey="id"
-        isSelection
         :column="columns"
         :tableData="dataList"
+        :tableLoading="tableLoading"
         :page="{
           current: pagination.currentPage,
           size: pagination.pageSize,
           total: pagination.total,
         }"
-        @selection-change="handleSelectionChange"
         @pagination="changePage"
       >
         <template #amount="{ row }">
@@ -56,54 +67,123 @@
         <template #totalAmount="{ row }">
           <span class="text-success">楼{{ formatMoney(row.totalAmount) }}</span>
         </template>
-        <template #certifyStatus="{ row }">
-          <el-tag :type="getCertifyStatusType(row.certifyStatus)">{{ getCertifyStatusLabel(row.certifyStatus) }}</el-tag>
+        <template #status="{ row }">
+          <el-tag :type="getStatusType(row.status)" effect="light" round>
+            {{ getStatusLabel(row.status) }}
+          </el-tag>
         </template>
         <template #operation="{ row }">
           <el-button type="primary" link @click="view(row)">鏌ョ湅</el-button>
-          <el-button type="primary" link @click="edit(row)">缂栬緫</el-button>
-          <el-button type="success" link @click="handleCertify(row)" v-if="row.certifyStatus === 'uncertified'">璁よ瘉</el-button>
+          <el-button type="warning" link @click="handleCancel(row)" v-if="isNormalStatus(row.status)">浣滃簾</el-button>
+          <el-button type="danger" link @click="handleDelete(row)">鍒犻櫎</el-button>
         </template>
       </PIMTable>
     </div>
 
-    <FormDialog :title="dialogTitle" v-model="dialogVisible" width="800px" @confirm="submitForm" @cancel="dialogVisible = false">
+    <FormDialog
+      :title="dialogTitle"
+      v-model="dialogVisible"
+      width="800px"
+      :operation-type="isView ? 'detail' : ''"
+      @confirm="submitForm"
+      @cancel="closeDialog"
+    >
       <el-form :model="form" :rules="rules" ref="formRef" label-width="120px">
-        <el-row :gutter="20">
+        <el-row v-if="isView" :gutter="20">
           <el-col :span="12">
-            <el-form-item label="鍙戠エ浠g爜" prop="invoiceCode">
-              <el-input v-model="form.invoiceCode" placeholder="璇疯緭鍏ュ彂绁ㄤ唬鐮�" />
-            </el-form-item>
-          </el-col>
-          <el-col :span="12">
-            <el-form-item label="鍙戠エ鍙风爜" prop="invoiceNo">
-              <el-input v-model="form.invoiceNo" placeholder="璇疯緭鍏ュ彂绁ㄥ彿鐮�" />
+            <el-form-item label="鐘舵��">
+              <el-tag :type="getStatusType(form.status)" effect="light" round>
+                {{ getStatusLabel(form.status) }}
+              </el-tag>
             </el-form-item>
           </el-col>
         </el-row>
         <el-row :gutter="20">
           <el-col :span="12">
+            <el-form-item label="鍙戠エ鍙风爜" prop="invoiceNo">
+              <el-input v-model="form.invoiceNo" placeholder="璇疯緭鍏ュ彂绁ㄥ彿鐮�" :disabled="isView" />
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
             <el-form-item label="渚涘簲鍟�" prop="supplierId">
-              <el-select v-model="form.supplierId" placeholder="璇烽�夋嫨渚涘簲鍟�" style="width: 100%;">
-                <el-option v-for="item in supplierList" :key="item.id" :label="item.name" :value="item.id" />
+              <el-select
+                v-model="form.supplierId"
+                placeholder="璇烽�夋嫨渚涘簲鍟�"
+                style="width: 100%;"
+                filterable
+                :disabled="isView"
+                @change="handleSupplierChange"
+              >
+                <el-option
+                  v-for="item in supplierList"
+                  :key="item.id"
+                  :label="item.supplierName"
+                  :value="item.id"
+                />
               </el-select>
+            </el-form-item>
+          </el-col>
+        </el-row>
+        <el-row :gutter="20">
+          <el-col :span="12">
+            <el-form-item label="鍏宠仈鍏ュ簱鍗�" prop="stockInRecordIds">
+              <el-input
+                :model-value="inboundBatchDisplayText"
+                placeholder="璇峰厛閫夋嫨渚涘簲鍟�"
+                readonly
+                :disabled="!form.supplierId || isView"
+                class="inbound-batch-input"
+                @click="handleInboundInputClick"
+              >
+                <template v-if="!isView" #append>
+                  <el-button
+                    :disabled="!form.supplierId"
+                    :loading="inboundBatchLoading"
+                    @click.stop="openInboundSelectDialog"
+                  >
+                    閫夋嫨
+                  </el-button>
+                </template>
+              </el-input>
             </el-form-item>
           </el-col>
           <el-col :span="12">
             <el-form-item label="寮�绁ㄦ棩鏈�" prop="invoiceDate">
-              <el-date-picker v-model="form.invoiceDate" type="date" placeholder="閫夋嫨鏃ユ湡" value-format="YYYY-MM-DD" style="width: 100%;" />
+              <el-date-picker
+                v-model="form.invoiceDate"
+                type="date"
+                placeholder="閫夋嫨鏃ユ湡"
+                value-format="YYYY-MM-DD"
+                style="width: 100%;"
+                :disabled="isView"
+              />
             </el-form-item>
           </el-col>
         </el-row>
         <el-row :gutter="20">
-          <el-col :span="8">
-            <el-form-item label="閲戦(涓嶅惈绋�)" prop="amount">
-              <el-input-number v-model="form.amount" :min="0" :precision="2" style="width: 100%;" @change="calculateTax" />
+          <el-col :span="12">
+            <el-form-item label="鍙戠エ绫诲瀷" prop="invoiceType">
+              <el-select
+                v-model="form.invoiceType"
+                placeholder="璇烽�夋嫨鍙戠エ绫诲瀷"
+                style="width: 100%;"
+                :disabled="isView"
+              >
+                <el-option label="澧炲�肩◣涓撶敤鍙戠エ" value="澧炲�肩◣涓撶敤鍙戠エ" />
+                <el-option label="澧炲�肩◣鏅�氬彂绁�" value="澧炲�肩◣鏅�氬彂绁�" />
+                <el-option label="鐢靛瓙鍙戠エ" value="鐢靛瓙鍙戠エ" />
+              </el-select>
             </el-form-item>
           </el-col>
-          <el-col :span="8">
+          <el-col :span="12">
             <el-form-item label="绋庣巼" prop="taxRate">
-              <el-select v-model="form.taxRate" placeholder="璇烽�夋嫨绋庣巼" style="width: 100%;" @change="calculateTax">
+              <el-select
+                v-model="form.taxRate"
+                placeholder="璇烽�夋嫨绋庣巼"
+                style="width: 100%;"
+                :disabled="isView"
+                @change="handleTaxRateChange"
+              >
                 <el-option
                   v-for="dict in tax_rate"
                   :key="dict.value"
@@ -113,47 +193,109 @@
               </el-select>
             </el-form-item>
           </el-col>
-          <el-col :span="8">
-            <el-form-item label="绋庨">
-              <el-input v-model="form.taxAmount" disabled />
-            </el-form-item>
-          </el-col>
         </el-row>
         <el-row :gutter="20">
-          <el-col :span="12">
-            <el-form-item label="璁よ瘉鐘舵��" prop="certifyStatus">
-              <el-select v-model="form.certifyStatus" placeholder="璇烽�夋嫨璁よ瘉鐘舵��" style="width: 100%;" disabled>
-                <el-option label="鏈璇�" value="uncertified" />
-                <el-option label="宸茶璇�" value="certified" />
-                <el-option label="璁よ瘉澶辫触" value="failed" />
-              </el-select>
+          <el-col :span="8">
+            <el-form-item label="閲戦(涓嶅惈绋�)" prop="amount">
+              <el-input-number
+                v-model="form.amount"
+                :min="0"
+                :precision="2"
+                style="width: 100%;"
+                :disabled="isView"
+                placeholder="鏍规嵁鍏ュ簱鍗曞惈绋庨噾棰濊嚜鍔ㄦ崲绠楋紝鍙慨鏀�"
+                @change="calculateTaxFromExclusive"
+              />
             </el-form-item>
           </el-col>
-          <el-col :span="12">
-            <el-form-item label="璁よ瘉鏃ユ湡" prop="certifyDate">
-              <el-date-picker v-model="form.certifyDate" type="date" placeholder="閫夋嫨鏃ユ湡" value-format="YYYY-MM-DD" style="width: 100%;" disabled />
+          <el-col :span="8">
+            <el-form-item label="绋庨">
+              <el-input-number
+                v-model="form.taxAmount"
+                :min="0"
+                :precision="2"
+                :controls="false"
+                style="width: 100%;"
+                disabled
+              />
+            </el-form-item>
+          </el-col>
+          <el-col :span="8">
+            <el-form-item label="浠风◣鍚堣">
+              <el-input-number
+                v-model="form.totalAmount"
+                :min="0"
+                :precision="2"
+                :controls="false"
+                style="width: 100%;"
+                disabled
+              />
             </el-form-item>
           </el-col>
         </el-row>
         <el-form-item label="鍙戠エ鍐呭" prop="content">
-          <el-input v-model="form.content" type="textarea" :rows="3" placeholder="璇疯緭鍏ュ彂绁ㄥ唴瀹�" />
+          <el-input v-model="form.content" type="textarea" :rows="3" placeholder="璇疯緭鍏ュ彂绁ㄥ唴瀹�" :disabled="isView" />
         </el-form-item>
         <el-form-item label="澶囨敞" prop="remark">
-          <el-input v-model="form.remark" type="textarea" :rows="2" placeholder="璇疯緭鍏ュ娉�" />
+          <el-input v-model="form.remark" type="textarea" :rows="2" placeholder="璇疯緭鍏ュ娉�" :disabled="isView" />
         </el-form-item>
       </el-form>
-      <template #footer>
-        <el-button type="primary" @click="submitForm">纭畾</el-button>
-        <el-button @click="dialogVisible = false">鍙栨秷</el-button>
+      <template v-if="!isView" #footer>
+        <el-button type="primary" :loading="submitLoading" @click="submitForm">纭畾</el-button>
+        <el-button @click="closeDialog">鍙栨秷</el-button>
       </template>
     </FormDialog>
+
+    <el-dialog
+      v-model="inboundSelectVisible"
+      title="閫夋嫨鍏ュ簱鍗曞彿"
+      width="1100px"
+      append-to-body
+      destroy-on-close
+      :close-on-click-modal="false"
+      @closed="handleInboundDialogClosed"
+    >
+      <el-table
+        ref="inboundTableRef"
+        v-loading="inboundBatchLoading"
+        :data="inboundBatchList"
+        row-key="id"
+        border
+        stripe
+        max-height="480"
+        @selection-change="handleInboundDialogSelectionChange"
+      >
+        <el-table-column type="selection" width="55" align="center" />
+        <el-table-column prop="inboundBatches" label="鍏ュ簱鍗曞彿" min-width="140" show-overflow-tooltip />
+        <el-table-column prop="supplierName" label="渚涘簲鍟�" min-width="120" show-overflow-tooltip />
+        <el-table-column prop="productName" label="浜у搧鍚嶇О" min-width="120" show-overflow-tooltip />
+        <el-table-column prop="specificationModel" label="瑙勬牸鍨嬪彿" min-width="140" show-overflow-tooltip />
+        <el-table-column prop="purchaseContractNumber" label="閲囪喘璁㈠崟鍙�" min-width="140" show-overflow-tooltip />
+        <el-table-column prop="inboundDate" label="鍏ュ簱鏃ユ湡" width="110" align="center" />
+        <el-table-column prop="inboundAmount" label="鍏ュ簱閲戦(鍚◣)" width="120" align="right">
+          <template #default="{ row }">楼{{ formatMoney(getInboundRowTaxInclusiveAmount(row)) }}</template>
+        </el-table-column>
+      </el-table>
+      <template #footer>
+        <el-button type="primary" @click="confirmInboundSelection">纭畾</el-button>
+        <el-button @click="inboundSelectVisible = false">鍙栨秷</el-button>
+      </template>
+    </el-dialog>
   </div>
 </template>
 
 <script setup>
-import { ref, reactive, onMounted, getCurrentInstance } from "vue";
+import { ref, reactive, computed, onMounted, nextTick, getCurrentInstance } from "vue";
 import { ElMessage, ElMessageBox } from "element-plus";
 import FormDialog from "@/components/Dialog/FormDialog.vue";
+import { getOptions } from "@/api/procurementManagement/procurementLedger.js";
+import {
+  getInboundBatchesBySupplier,
+  addAccountPurchaseInvoice,
+  listPageAccountPurchaseInvoice,
+  cancelAccountPurchaseInvoice,
+  deleteAccountPurchaseInvoice,
+} from "@/api/financialManagement/accountPurchaseInvoice.js";
 
 defineOptions({
   name: "杩涢」鍙戠エ",
@@ -163,10 +305,10 @@
 const { tax_rate } = proxy.useDict("tax_rate");
 
 const filters = reactive({
-  invoiceCode: "",
-  invoiceNo: "",
+  invoiceNumber: "",
   supplierId: "",
-  certifyStatus: "",
+  dateRange: [],
+  status: "",
 });
 
 const pagination = reactive({
@@ -176,211 +318,601 @@
 });
 
 const columns = [
-  { label: "鍙戠エ浠g爜", prop: "invoiceCode", width: "130" },
-  { label: "鍙戠エ鍙风爜", prop: "invoiceNo", width: "120" },
+  { label: "鍙戠エ鍙风爜", prop: "invoiceNo", width: "140" },
   { label: "渚涘簲鍟�", prop: "supplierName", width: "180" },
   { label: "寮�绁ㄦ棩鏈�", prop: "invoiceDate", width: "120" },
-  { label: "閲戦", prop: "amount", slot: "amount" },
-  { label: "绋庨", prop: "taxAmount", slot: "taxAmount" },
-  { label: "浠风◣鍚堣", prop: "totalAmount", slot: "totalAmount" },
-  { label: "璁よ瘉鐘舵��", prop: "certifyStatus", slot: "certifyStatus" },
-  { label: "鎿嶄綔", prop: "operation", slot: "operation", width: "180", fixed: "right" },
+  { label: "閲戦", prop: "amount", dataType: "slot", slot: "amount" },
+  { label: "绋庨", prop: "taxAmount", dataType: "slot", slot: "taxAmount" },
+  { label: "浠风◣鍚堣", prop: "totalAmount", dataType: "slot", slot: "totalAmount" },
+  { label: "鍙戠エ绫诲瀷", prop: "invoiceType", width: "130" },
+  { label: "鐘舵��", prop: "status", dataType: "slot", slot: "status", width: "90", align: "center" },
+  { label: "鎿嶄綔", prop: "operation", dataType: "slot", slot: "operation", width: "200", fixed: "right" },
 ];
 
 const dataList = ref([]);
-const selectedRows = ref([]);
+const tableLoading = ref(false);
 const dialogVisible = ref(false);
 const dialogTitle = ref("");
 const formRef = ref(null);
-const isEdit = ref(false);
-const currentId = ref(null);
+const isView = ref(false);
+const submitLoading = ref(false);
+const supplierList = ref([]);
 
-const supplierList = [
-  { id: 1, name: "鍖椾含鍘熸潗鏂欎緵搴斿晢" },
-  { id: 2, name: "涓婃捣鐢靛瓙鍏冨櫒浠跺叕鍙�" },
-  { id: 3, name: "骞垮窞鍖呰鏉愭枡鍘�" },
-  { id: 4, name: "娣卞湷浜旈噾閰嶄欢鍏徃" },
-];
+const inboundBatchList = ref([]);
+const inboundBatchOptions = ref([]);
+const inboundBatchLoading = ref(false);
+const inboundSelectVisible = ref(false);
+const inboundTableRef = ref(null);
+const dialogInboundSelection = ref([]);
+
+const STATUS_LABEL_MAP = { 0: "姝e父", 1: "浣滃簾" };
+const STATUS_TYPE_MAP = { 0: "success", 1: "info" };
 
 const form = reactive({
-  invoiceCode: "",
   invoiceNo: "",
   supplierId: "",
   invoiceDate: "",
-  amount: 0,
+  invoiceType: "澧炲�肩◣涓撶敤鍙戠エ",
   taxRate: 13,
+  amount: 0,
   taxAmount: 0,
   totalAmount: 0,
-  certifyStatus: "uncertified",
-  certifyDate: "",
   content: "",
   remark: "",
+  stockInRecordIds: [],
+  inboundBatches: "",
+  storageAttachmentId: undefined,
+  status: 0,
 });
 
 const rules = {
-  invoiceCode: [{ required: true, message: "璇疯緭鍏ュ彂绁ㄤ唬鐮�", trigger: "blur" }],
   invoiceNo: [{ required: true, message: "璇疯緭鍏ュ彂绁ㄥ彿鐮�", trigger: "blur" }],
   supplierId: [{ required: true, message: "璇烽�夋嫨渚涘簲鍟�", trigger: "change" }],
+  stockInRecordIds: [{ required: true, type: "array", min: 1, message: "璇烽�夋嫨鍏宠仈鍏ュ簱鍗�", trigger: "change" }],
   invoiceDate: [{ required: true, message: "璇烽�夋嫨寮�绁ㄦ棩鏈�", trigger: "change" }],
-  amount: [{ required: true, message: "璇疯緭鍏ラ噾棰�", trigger: "blur" }],
+  invoiceType: [{ required: true, message: "璇烽�夋嫨鍙戠エ绫诲瀷", trigger: "change" }],
   taxRate: [{ required: true, message: "璇烽�夋嫨绋庣巼", trigger: "change" }],
+  amount: [{ required: true, message: "璇疯緭鍏ラ噾棰�", trigger: "blur" }],
 };
-
-const mockData = [
-  { id: 1, invoiceCode: "0440021001", invoiceNo: "12345678", supplierId: 1, supplierName: "鍖椾含鍘熸潗鏂欎緵搴斿晢", invoiceDate: "2024-01-08", amount: 8000, taxRate: 13, taxAmount: 1040, totalAmount: 9040, certifyStatus: "certified", certifyDate: "2024-01-15", content: "鍘熸潗鏂欓噰璐�", remark: "" },
-  { id: 2, invoiceCode: "0440021002", invoiceNo: "87654321", supplierId: 2, supplierName: "涓婃捣鐢靛瓙鍏冨櫒浠跺叕鍙�", invoiceDate: "2024-01-10", amount: 12000, taxRate: 13, taxAmount: 1560, totalAmount: 13560, certifyStatus: "uncertified", certifyDate: "", content: "鐢靛瓙鍏冨櫒浠�", remark: "" },
-  { id: 3, invoiceCode: "0440021003", invoiceNo: "11112222", supplierId: 3, supplierName: "骞垮窞鍖呰鏉愭枡鍘�", invoiceDate: "2024-01-12", amount: 3500, taxRate: 13, taxAmount: 455, totalAmount: 3955, certifyStatus: "certified", certifyDate: "2024-01-18", content: "鍖呰鏉愭枡", remark: "" },
-];
 
 const formatMoney = (value) => {
   if (value === undefined || value === null) return "0.00";
   return Number(value).toFixed(2).replace(/\B(?=(\d{3})+(?!\d))/g, ",");
 };
 
-const calculateTax = () => {
+const normalizeStatus = (status) => {
+  if (status === undefined || status === null || status === "") return 0;
+  const num = Number(status);
+  return Number.isNaN(num) ? 0 : num;
+};
+
+const isNormalStatus = (status) => normalizeStatus(status) === 0;
+
+const getStatusLabel = (status) => STATUS_LABEL_MAP[normalizeStatus(status)] ?? "姝e父";
+
+const getStatusType = (status) => STATUS_TYPE_MAP[normalizeStatus(status)] ?? "success";
+
+const parseStockInRecordIds = (value) => {
+  if (!value) return [];
+  if (Array.isArray(value)) return value;
+  return String(value)
+    .split(/[,锛宂/)
+    .map((s) => s.trim())
+    .filter(Boolean)
+    .map((s) => (/^\d+$/.test(s) ? Number(s) : s));
+};
+
+const formatInboundBatches = (value) => {
+  if (value === undefined || value === null || value === "") return "";
+  if (Array.isArray(value)) return value.filter(Boolean).join("銆�");
+  return String(value)
+    .split(/[,锛宂/)
+    .map((s) => s.trim())
+    .filter(Boolean)
+    .join("銆�");
+};
+
+const isSameInboundId = (a, b) => String(a) === String(b);
+
+const getInboundRowId = (row) => row?.id ?? row?.stockInRecordId;
+
+/** 鍏ュ簱鍗曢噾棰濅负鍚◣浠� */
+const getInboundRowTaxInclusiveAmount = (row) =>
+  Number(row?.inboundAmount ?? row?.taxInclusivePrice ?? row?.totalAmount ?? 0);
+
+const normalizeInboundBatchOptions = (data) => {
+  const list = Array.isArray(data) ? data : [];
+  return list.map((item, index) => {
+    if (typeof item === "string" || typeof item === "number") {
+      const text = String(item);
+      return { label: text, value: text, inboundAmount: 0 };
+    }
+    const label =
+      item.inboundBatches ?? item.batchNo ?? item.inboundNo ?? item.label ?? `鍏ュ簱鍗�${index + 1}`;
+    const value = item.id ?? item.stockInRecordId ?? label;
+    return {
+      label: String(label),
+      value,
+      inboundAmount: getInboundRowTaxInclusiveAmount(item),
+    };
+  });
+};
+
+/** 涓嶅惈绋庨噾棰濆彉鏇达細绋庨銆佷环绋庡悎璁℃鍚戣绠� */
+const calculateTaxFromExclusive = () => {
   form.taxAmount = Number((form.amount * form.taxRate / 100).toFixed(2));
   form.totalAmount = Number((form.amount + form.taxAmount).toFixed(2));
 };
 
-const getCertifyStatusLabel = (status) => {
-  const map = { uncertified: "鏈璇�", certified: "宸茶璇�", failed: "璁よ瘉澶辫触" };
-  return map[status] || status;
+/** 浠风◣鍚堣鍙樻洿锛氭寜绋庣巼鍙嶇畻涓嶅惈绋庨噾棰濄�佺◣棰� */
+const calculateTaxFromInclusive = (inclusiveTotal) => {
+  const total = Number(inclusiveTotal ?? form.totalAmount ?? 0);
+  if (total <= 0) {
+    form.amount = 0;
+    form.taxAmount = 0;
+    form.totalAmount = 0;
+    return;
+  }
+  const rate = Number(form.taxRate) / 100;
+  form.totalAmount = Number(total.toFixed(2));
+  form.amount = Number((form.totalAmount / (1 + rate)).toFixed(2));
+  form.taxAmount = Number((form.totalAmount - form.amount).toFixed(2));
 };
 
-const getCertifyStatusType = (status) => {
-  const map = { uncertified: "info", certified: "success", failed: "danger" };
-  return map[status] || "";
+const handleTaxRateChange = () => {
+  if (form.totalAmount > 0) {
+    calculateTaxFromInclusive(form.totalAmount);
+  } else {
+    calculateTaxFromExclusive();
+  }
+};
+
+/** 鏍规嵁宸查�夊叆搴撳崟姹囨�诲惈绋庨噾棰濓紝鍙嶇畻涓嶅惈绋庨噾棰濅笌绋庨 */
+const syncInvoiceAmount = () => {
+  const selected = form.stockInRecordIds || [];
+  const sumFromOptions = inboundBatchOptions.value
+    .filter((opt) => selected.some((id) => isSameInboundId(id, opt.value)))
+    .reduce((acc, opt) => acc + (Number(opt.inboundAmount) || 0), 0);
+
+  let taxInclusiveSum = sumFromOptions;
+  if (taxInclusiveSum <= 0 && selected.length) {
+    taxInclusiveSum = inboundBatchList.value
+      .filter((row) => selected.some((id) => isSameInboundId(id, getInboundRowId(row))))
+      .reduce((acc, row) => acc + getInboundRowTaxInclusiveAmount(row), 0);
+  }
+
+  calculateTaxFromInclusive(taxInclusiveSum > 0 ? Number(taxInclusiveSum.toFixed(2)) : 0);
+};
+
+const inboundBatchDisplayText = computed(() => {
+  if (form.inboundBatches) return form.inboundBatches;
+  const ids = form.stockInRecordIds || [];
+  if (!ids.length) return "";
+  const labels = inboundBatchOptions.value
+    .filter((opt) => ids.some((id) => isSameInboundId(id, opt.value)))
+    .map((opt) => opt.label);
+  if (labels.length) return labels.join("銆�");
+  return ids.join("銆�");
+});
+
+const normalizeTableRow = (row) => ({
+  ...row,
+  invoiceNo: row.invoiceNumber ?? row.invoiceNo,
+  invoiceDate: row.issueDate ?? row.invoiceDate,
+  amount: row.taxExclusivelPrice ?? row.amount,
+  taxAmount: row.taxPrice ?? row.taxAmount,
+  totalAmount: row.taxInclusivePrice ?? row.totalAmount,
+  content: row.invoiceContent ?? row.content,
+  status: normalizeStatus(row.status),
+  stockInRecordIds: row.stockInRecordIds ?? "",
+  inboundBatches: formatInboundBatches(row.inboundBatches),
+});
+
+const toFormNumber = (val) => {
+  const n = Number(val);
+  return Number.isFinite(n) ? n : 0;
+};
+
+const resolveFormAmounts = (row) => {
+  let amount = toFormNumber(row.taxExclusivelPrice ?? row.amount);
+  let taxAmount = toFormNumber(row.taxPrice ?? row.taxAmount);
+  let totalAmount = toFormNumber(row.taxInclusivePrice ?? row.totalAmount);
+  const taxRate = toFormNumber(row.taxRate) || 13;
+
+  if (totalAmount > 0 && amount === 0 && taxAmount === 0) {
+    amount = Number((totalAmount / (1 + taxRate / 100)).toFixed(2));
+    taxAmount = Number((totalAmount - amount).toFixed(2));
+  } else if (totalAmount > 0 && amount > 0 && taxAmount === 0) {
+    taxAmount = Number((totalAmount - amount).toFixed(2));
+  } else if (amount > 0 && taxAmount === 0 && totalAmount === 0) {
+    taxAmount = Number((amount * taxRate / 100).toFixed(2));
+    totalAmount = Number((amount + taxAmount).toFixed(2));
+  } else if (amount > 0 && taxAmount > 0 && totalAmount === 0) {
+    totalAmount = Number((amount + taxAmount).toFixed(2));
+  }
+
+  return { amount, taxAmount, totalAmount };
+};
+
+const fillFormFromRow = (row) => {
+  const stockInRecordIds = parseStockInRecordIds(row.stockInRecordIds);
+  const { amount, taxAmount, totalAmount } = resolveFormAmounts(row);
+  Object.assign(form, {
+    invoiceNo: row.invoiceNo ?? row.invoiceNumber ?? "",
+    supplierId: row.supplierId,
+    invoiceDate: row.invoiceDate ?? row.issueDate ?? "",
+    invoiceType: row.invoiceType ?? "澧炲�肩◣涓撶敤鍙戠エ",
+    taxRate: row.taxRate ?? 13,
+    amount,
+    taxAmount,
+    totalAmount,
+    content: row.content ?? row.invoiceContent ?? "",
+    remark: row.remark ?? "",
+    stockInRecordIds,
+    inboundBatches: formatInboundBatches(row.inboundBatches),
+    storageAttachmentId: row.storageAttachmentId,
+    status: normalizeStatus(row.status),
+  });
+};
+
+const buildCancelPayload = (row) => ({
+  id: row.id,
+  invoiceNumber: row.invoiceNumber ?? row.invoiceNo,
+  taxRate: row.taxRate,
+  invoiceType: row.invoiceType,
+  issueDate: row.issueDate ?? row.invoiceDate,
+  taxExclusivelPrice: row.taxExclusivelPrice ?? row.amount,
+  taxPrice: row.taxPrice ?? row.taxAmount,
+  taxInclusivePrice: row.taxInclusivePrice ?? row.totalAmount,
+  remark: row.remark ?? "",
+  invoiceContent: row.invoiceContent ?? row.content,
+  supplierId: row.supplierId,
+  storageAttachmentId: row.storageAttachmentId,
+  stockInRecordIds: row.stockInRecordIds ?? "",
+  status: 1,
+});
+
+const buildSubmitPayload = () => ({
+  invoiceNumber: form.invoiceNo,
+  supplierId: form.supplierId,
+  issueDate: form.invoiceDate,
+  invoiceType: form.invoiceType,
+  taxRate: form.taxRate,
+  taxExclusivelPrice: form.amount,
+  taxPrice: form.taxAmount,
+  taxInclusivePrice: form.totalAmount,
+  invoiceContent: form.content,
+  remark: form.remark || "",
+  stockInRecordIds: (form.stockInRecordIds || []).join(","),
+  status: 0,
+  storageAttachmentId: form.storageAttachmentId,
+});
+
+const getSupplierList = () => {
+  getOptions().then((res) => {
+    if (res.code === 200) {
+      supplierList.value = res.data ?? [];
+    }
+  });
+};
+
+const appendFilterParams = (params) => {
+  if (filters.invoiceNumber) {
+    params.invoiceNumber = filters.invoiceNumber;
+  }
+  if (filters.supplierId) {
+    params.supplierId = filters.supplierId;
+  }
+  if (filters.dateRange?.length === 2) {
+    params.startDate = filters.dateRange[0];
+    params.endDate = filters.dateRange[1];
+  }
+  if (filters.status !== "" && filters.status != null) {
+    params.status = filters.status;
+  }
+  return params;
+};
+
+const buildListParams = () =>
+  appendFilterParams({
+    current: pagination.currentPage,
+    size: pagination.pageSize,
+  });
+
+const buildExportParams = () => appendFilterParams({});
+
+const handleExport = () => {
+  proxy.download(
+    "/accountPurchaseInvoice/exportAccountPurchaseInvoice",
+    buildExportParams(),
+    `杩涢」鍙戠エ_${Date.now()}.xlsx`
+  );
 };
 
 const getTableData = () => {
-  let result = [...mockData];
-  if (filters.invoiceCode) {
-    result = result.filter(item => item.invoiceCode.includes(filters.invoiceCode));
-  }
-  if (filters.invoiceNo) {
-    result = result.filter(item => item.invoiceNo.includes(filters.invoiceNo));
-  }
-  if (filters.supplierId) {
-    result = result.filter(item => item.supplierId === filters.supplierId);
-  }
-  if (filters.certifyStatus) {
-    result = result.filter(item => item.certifyStatus === filters.certifyStatus);
-  }
-  pagination.total = result.length;
-  dataList.value = result.slice((pagination.currentPage - 1) * pagination.pageSize, pagination.currentPage * pagination.pageSize);
+  tableLoading.value = true;
+  listPageAccountPurchaseInvoice(buildListParams())
+    .then((res) => {
+      if (res.code === 200) {
+        const records = res.data?.records ?? [];
+        dataList.value = records.map(normalizeTableRow);
+        pagination.total = res.data?.total ?? 0;
+      } else {
+        dataList.value = [];
+        pagination.total = 0;
+        ElMessage.error(res.msg || "鏌ヨ澶辫触");
+      }
+    })
+    .catch(() => {
+      dataList.value = [];
+      pagination.total = 0;
+      ElMessage.error("鏌ヨ澶辫触");
+    })
+    .finally(() => {
+      tableLoading.value = false;
+    });
 };
 
-const resetFilters = () => {
-  filters.invoiceCode = "";
-  filters.invoiceNo = "";
-  filters.supplierId = "";
-  filters.certifyStatus = "";
+const onSearch = () => {
   pagination.currentPage = 1;
   getTableData();
 };
 
-const changePage = ({ current, size }) => {
-  pagination.currentPage = current;
-  pagination.pageSize = size;
+const resetFilters = () => {
+  filters.invoiceNumber = "";
+  filters.supplierId = "";
+  filters.dateRange = [];
+  filters.status = "";
+  pagination.currentPage = 1;
   getTableData();
 };
 
-const handleSelectionChange = (selection) => {
-  selectedRows.value = selection;
+const changePage = ({ page, limit }) => {
+  pagination.currentPage = page;
+  pagination.pageSize = limit;
+  getTableData();
+};
+
+const closeDialog = () => {
+  dialogVisible.value = false;
+  isView.value = false;
+  inboundSelectVisible.value = false;
+};
+
+const resetForm = () => {
+  Object.assign(form, {
+    invoiceNo: "",
+    supplierId: "",
+    invoiceDate: new Date().toISOString().split("T")[0],
+    invoiceType: "澧炲�肩◣涓撶敤鍙戠エ",
+    taxRate: 13,
+    amount: 0,
+    taxAmount: 0,
+    totalAmount: 0,
+    content: "",
+    remark: "",
+    stockInRecordIds: [],
+    inboundBatches: "",
+    storageAttachmentId: undefined,
+    status: 0,
+  });
+  inboundBatchList.value = [];
+  inboundBatchOptions.value = [];
 };
 
 const add = () => {
-  isEdit.value = false;
+  isView.value = false;
   dialogTitle.value = "褰曞叆鍙戠エ";
-  Object.assign(form, {
-    invoiceCode: "",
-    invoiceNo: "",
-    supplierId: "",
-    invoiceDate: new Date().toISOString().split('T')[0],
-    amount: 0,
-    taxRate: 13,
-    taxAmount: 0,
-    totalAmount: 0,
-    certifyStatus: "uncertified",
-    certifyDate: "",
-    content: "",
-    remark: "",
-  });
-  dialogVisible.value = true;
-};
-
-const edit = (row) => {
-  isEdit.value = true;
-  currentId.value = row.id;
-  dialogTitle.value = "缂栬緫鍙戠エ";
-  Object.assign(form, row);
+  resetForm();
   dialogVisible.value = true;
 };
 
 const view = (row) => {
-  ElMessage.info(`鏌ョ湅鍙戠エ: ${row.invoiceCode}-${row.invoiceNo}`);
+  isView.value = true;
+  dialogTitle.value = "鏌ョ湅鍙戠エ";
+  fillFormFromRow(row);
+  if (row.supplierId) {
+    loadInboundBatches(row.supplierId, true, false);
+  }
+  dialogVisible.value = true;
 };
 
-const handleCertify = (row) => {
-  ElMessageBox.confirm("纭璁よ瘉璇ュ彂绁ㄥ悧锛�", "鎻愮ず", {
-    confirmButtonText: "纭",
+const handleCancel = (row) => {
+  ElMessageBox.confirm(`纭浣滃簾鍙戠エ銆�${row.invoiceNo ?? row.invoiceNumber}銆嶅悧锛焋, "浣滃簾纭", {
+    confirmButtonText: "纭畾",
     cancelButtonText: "鍙栨秷",
-    type: "info",
+    type: "warning",
   }).then(() => {
-    const index = mockData.findIndex(item => item.id === row.id);
-    if (index !== -1) {
-      mockData[index].certifyStatus = "certified";
-      mockData[index].certifyDate = new Date().toISOString().split('T')[0];
-    }
-    ElMessage.success("璁よ瘉鎴愬姛");
-    getTableData();
+    cancelAccountPurchaseInvoice(buildCancelPayload(row))
+      .then((res) => {
+        if (res.code === 200) {
+          ElMessage.success("浣滃簾鎴愬姛");
+          getTableData();
+        } else {
+          ElMessage.error(res.msg || "浣滃簾澶辫触");
+        }
+      })
+      .catch(() => {
+        ElMessage.error("浣滃簾澶辫触");
+      });
   });
 };
 
-const handleBatchCertify = () => {
-  ElMessageBox.confirm(`纭鎵归噺璁よ瘉閫変腑鐨� ${selectedRows.value.length} 寮犲彂绁ㄥ悧锛焋, "鎻愮ず", {
-    confirmButtonText: "纭",
+const handleDelete = (row) => {
+  ElMessageBox.confirm(`纭鍒犻櫎鍙戠エ銆�${row.invoiceNo ?? row.invoiceNumber}銆嶅悧锛焋, "鍒犻櫎纭", {
+    confirmButtonText: "纭畾",
     cancelButtonText: "鍙栨秷",
-    type: "info",
+    type: "warning",
   }).then(() => {
-    selectedRows.value.forEach(row => {
-      const index = mockData.findIndex(item => item.id === row.id);
-      if (index !== -1 && mockData[index].certifyStatus === "uncertified") {
-        mockData[index].certifyStatus = "certified";
-        mockData[index].certifyDate = new Date().toISOString().split('T')[0];
-      }
-    });
-    ElMessage.success("鎵归噺璁よ瘉鎴愬姛");
-    getTableData();
+    deleteAccountPurchaseInvoice([row.id])
+      .then((res) => {
+        if (res.code === 200) {
+          ElMessage.success("鍒犻櫎鎴愬姛");
+          getTableData();
+        } else {
+          ElMessage.error(res.msg || "鍒犻櫎澶辫触");
+        }
+      })
+      .catch(() => {
+        ElMessage.error("鍒犻櫎澶辫触");
+      });
   });
-};
-
-const handleOut = () => {
-  ElMessage.success("瀵煎嚭鎴愬姛");
 };
 
 const submitForm = () => {
-  formRef.value.validate((valid) => {
-    if (valid) {
-      const supplier = supplierList.find(item => item.id === form.supplierId);
-      if (isEdit.value) {
-        const index = mockData.findIndex(item => item.id === currentId.value);
-        if (index !== -1) {
-          mockData[index] = { ...mockData[index], ...form, supplierName: supplier?.name };
+  formRef.value?.validate((valid) => {
+    if (!valid) return;
+    submitLoading.value = true;
+    addAccountPurchaseInvoice(buildSubmitPayload())
+      .then((res) => {
+        if (res.code === 200) {
+          ElMessage.success("褰曞叆鎴愬姛");
+          closeDialog();
+          pagination.currentPage = 1;
+          getTableData();
+        } else {
+          ElMessage.error(res.msg || "褰曞叆澶辫触");
         }
-        ElMessage.success("缂栬緫鎴愬姛");
-      } else {
-        const newId = mockData.length > 0 ? Math.max(...mockData.map(item => item.id)) + 1 : 1;
-        mockData.push({ id: newId, ...form, supplierName: supplier?.name });
-        ElMessage.success("褰曞叆鎴愬姛");
-      }
-      dialogVisible.value = false;
-      getTableData();
-    }
+      })
+      .catch(() => {
+        ElMessage.error("褰曞叆澶辫触");
+      })
+      .finally(() => {
+        submitLoading.value = false;
+      });
   });
 };
 
+const ensureInboundOptionsForSelected = () => {
+  const ids = form.stockInRecordIds || [];
+  ids.forEach((id) => {
+    const exists = inboundBatchOptions.value.some((opt) => isSameInboundId(opt.value, id));
+    if (exists) return;
+    const fromList = inboundBatchList.value.find((row) => isSameInboundId(getInboundRowId(row), id));
+    if (fromList) {
+      const [option] = normalizeInboundBatchOptions([fromList]);
+      if (option) inboundBatchOptions.value.push(option);
+      return;
+    }
+    inboundBatchOptions.value.push({
+      label: String(id),
+      value: id,
+      inboundAmount: 0,
+    });
+  });
+};
+
+const restoreInboundTableSelection = () => {
+  nextTick(() => {
+    const table = inboundTableRef.value;
+    if (!table) return;
+    table.clearSelection();
+    const selectedIds = new Set((form.stockInRecordIds || []).map((id) => String(id)));
+    inboundBatchList.value.forEach((row) => {
+      const rowId = getInboundRowId(row);
+      if (rowId !== undefined && rowId !== null && selectedIds.has(String(rowId))) {
+        table.toggleRowSelection(row, true);
+      }
+    });
+  });
+};
+
+const loadInboundBatches = (supplierId, keepSelected = false, syncAmount = true) => {
+  if (!supplierId) {
+    inboundBatchList.value = [];
+    inboundBatchOptions.value = [];
+    if (!keepSelected) {
+      form.stockInRecordIds = [];
+      form.inboundBatches = "";
+      form.amount = 0;
+      form.taxAmount = 0;
+      form.totalAmount = 0;
+    }
+    return Promise.resolve();
+  }
+  inboundBatchLoading.value = true;
+  return getInboundBatchesBySupplier({ supplierId })
+    .then((res) => {
+      if (res.code === 200) {
+        const list = res.data?.records ?? res.data ?? [];
+        inboundBatchList.value = Array.isArray(list) ? list : [];
+        inboundBatchOptions.value = normalizeInboundBatchOptions(list);
+      } else {
+        inboundBatchList.value = [];
+        inboundBatchOptions.value = [];
+      }
+    })
+    .catch(() => {
+      inboundBatchList.value = [];
+      inboundBatchOptions.value = [];
+    })
+    .finally(() => {
+      inboundBatchLoading.value = false;
+      if (keepSelected) {
+        ensureInboundOptionsForSelected();
+        restoreInboundTableSelection();
+        if (syncAmount && !isView.value) {
+          syncInvoiceAmount();
+        }
+      }
+    });
+};
+
+const handleSupplierChange = (supplierId) => {
+  form.stockInRecordIds = [];
+  form.inboundBatches = "";
+  form.amount = 0;
+  form.taxAmount = 0;
+  form.totalAmount = 0;
+  loadInboundBatches(supplierId);
+};
+
+const handleInboundInputClick = () => {
+  if (isView.value) return;
+  openInboundSelectDialog();
+};
+
+const openInboundSelectDialog = () => {
+  if (!form.supplierId || isView.value) return;
+  inboundSelectVisible.value = true;
+  loadInboundBatches(form.supplierId, true).then(() => {
+    restoreInboundTableSelection();
+  });
+};
+
+const handleInboundDialogSelectionChange = (selection) => {
+  dialogInboundSelection.value = selection;
+};
+
+const confirmInboundSelection = () => {
+  if (dialogInboundSelection.value.length === 0) {
+    ElMessage.warning("璇疯嚦灏戦�夋嫨涓�鏉″叆搴撳崟");
+    return;
+  }
+  form.stockInRecordIds = dialogInboundSelection.value
+    .map((row) => getInboundRowId(row))
+    .filter((id) => id !== undefined && id !== null);
+  form.inboundBatches = dialogInboundSelection.value
+    .map((row) => row.inboundBatches ?? row.batchNo ?? "")
+    .filter(Boolean)
+    .join("銆�");
+  dialogInboundSelection.value.forEach((row) => {
+    const [option] = normalizeInboundBatchOptions([row]);
+    if (option && !inboundBatchOptions.value.some((opt) => isSameInboundId(opt.value, option.value))) {
+      inboundBatchOptions.value.push(option);
+    }
+  });
+  inboundSelectVisible.value = false;
+  syncInvoiceAmount();
+  formRef.value?.validateField("stockInRecordIds");
+};
+
+const handleInboundDialogClosed = () => {
+  dialogInboundSelection.value = [];
+};
+
 onMounted(() => {
+  getSupplierList();
   getTableData();
 });
 </script>
@@ -406,4 +938,8 @@
   color: #67c23a;
   font-weight: bold;
 }
+
+.inbound-batch-input :deep(.el-input__wrapper) {
+  cursor: pointer;
+}
 </style>
diff --git a/src/views/financialManagement/payable/payment.vue b/src/views/financialManagement/payable/payment.vue
index d4774fe..d762ae9 100644
--- a/src/views/financialManagement/payable/payment.vue
+++ b/src/views/financialManagement/payable/payment.vue
@@ -2,47 +2,60 @@
   <div class="app-container">
     <el-form :model="filters" :inline="true">
       <el-form-item label="浠樻鍗曞彿:">
-        <el-input v-model="filters.paymentCode" placeholder="璇疯緭鍏ヤ粯娆惧崟鍙�" clearable style="width: 200px;" />
+        <el-input v-model="filters.paymentNumber" placeholder="璇疯緭鍏ヤ粯娆惧崟鍙�" clearable style="width: 200px;" />
       </el-form-item>
       <el-form-item label="渚涘簲鍟�:">
-        <el-select v-model="filters.supplierId" placeholder="璇烽�夋嫨渚涘簲鍟�" clearable style="width: 200px;">
-          <el-option v-for="item in supplierList" :key="item.id" :label="item.name" :value="item.id" />
+        <el-select v-model="filters.supplierId" placeholder="璇烽�夋嫨渚涘簲鍟�" clearable filterable style="width: 200px;">
+          <el-option
+            v-for="item in supplierList"
+            :key="item.id"
+            :label="item.supplierName"
+            :value="item.id"
+          />
         </el-select>
       </el-form-item>
       <el-form-item label="浠樻鏂瑰紡:">
         <el-select v-model="filters.paymentMethod" placeholder="璇烽�夋嫨浠樻鏂瑰紡" clearable style="width: 150px;">
-          <el-option label="閾惰杞处" value="bank_transfer" />
-          <el-option label="鐜伴噾" value="cash" />
-          <el-option label="鏀エ" value="check" />
-          <el-option label="姹囩エ" value="draft" />
+          <el-option
+            v-for="item in checkout_payment"
+            :key="item.value"
+            :label="item.label"
+            :value="item.value"
+          />
         </el-select>
       </el-form-item>
-      <el-form-item label="鐘舵��:">
-        <el-select v-model="filters.status" placeholder="璇烽�夋嫨鐘舵��" clearable style="width: 150px;">
-          <el-option label="寰呬粯娆�" value="pending" />
-          <el-option label="宸插畬鎴�" value="completed" />
-          <el-option label="宸插彇娑�" value="cancelled" />
-        </el-select>
+      <el-form-item label="浠樻鏃ユ湡:">
+        <el-date-picker
+          v-model="filters.dateRange"
+          type="daterange"
+          value-format="YYYY-MM-DD"
+          format="YYYY-MM-DD"
+          range-separator="鑷�"
+          start-placeholder="寮�濮嬫棩鏈�"
+          end-placeholder="缁撴潫鏃ユ湡"
+          clearable
+          style="width: 240px;"
+        />
       </el-form-item>
       <el-form-item>
-        <el-button type="primary" @click="getTableData">鎼滅储</el-button>
+        <el-button type="primary" @click="onSearch">鎼滅储</el-button>
         <el-button @click="resetFilters">閲嶇疆</el-button>
       </el-form-item>
     </el-form>
     <div class="table_list">
       <div class="actions">
         <div>
-          <el-statistic title="鏈湡浠樻鍚堣" :value="totalPaymentAmount" precision="2" prefix="楼" />
+          <el-statistic title="鏈〉浠樻鍚堣" :value="totalPaymentAmount" :precision="2" prefix="楼" />
         </div>
         <div>
-          <el-button type="primary" @click="add" icon="Plus">鏂板浠樻</el-button>
-          <el-button @click="handleOut" icon="Download">瀵煎嚭</el-button>
+          <el-button @click="handleExport" icon="Download">瀵煎嚭</el-button>
         </div>
       </div>
       <PIMTable
         rowKey="id"
         :column="columns"
         :tableData="dataList"
+        :tableLoading="tableLoading"
         :page="{
           current: pagination.currentPage,
           size: pagination.pageSize,
@@ -56,105 +69,35 @@
         <template #paymentMethod="{ row }">
           <el-tag>{{ getPaymentMethodLabel(row.paymentMethod) }}</el-tag>
         </template>
-        <template #status="{ row }">
-          <el-tag :type="row.status === 'completed' ? 'success' : row.status === 'pending' ? 'warning' : 'info'">
-            {{ row.status === 'completed' ? '宸插畬鎴�' : row.status === 'pending' ? '寰呬粯娆�' : '宸插彇娑�' }}
-          </el-tag>
-        </template>
         <template #operation="{ row }">
-          <el-button type="primary" link @click="view(row)">鏌ョ湅</el-button>
-          <el-button type="primary" link @click="edit(row)" v-if="row.status === 'pending'">缂栬緫</el-button>
-          <el-button type="success" link @click="handleComplete(row)" v-if="row.status === 'pending'">瀹屾垚</el-button>
-          <el-button type="danger" link @click="handleCancel(row)" v-if="row.status === 'pending'">鍙栨秷</el-button>
+          <el-button type="danger" link @click="handleDelete(row)">鍒犻櫎</el-button>
         </template>
       </PIMTable>
     </div>
-
-    <FormDialog :title="dialogTitle" v-model="dialogVisible" width="800px" @confirm="submitForm" @cancel="dialogVisible = false">
-      <el-form :model="form" :rules="rules" ref="formRef" label-width="120px">
-        <el-row :gutter="20">
-          <el-col :span="12">
-            <el-form-item label="浠樻鍗曞彿" prop="paymentCode">
-              <el-input v-model="form.paymentCode" placeholder="绯荤粺鑷姩鐢熸垚" disabled />
-            </el-form-item>
-          </el-col>
-          <el-col :span="12">
-            <el-form-item label="鍏宠仈鐢宠鍗�" prop="applyCode">
-              <el-select v-model="form.applyCode" placeholder="璇烽�夋嫨鍏宠仈鐢宠鍗�" style="width: 100%;" :disabled="isEdit">
-                <el-option v-for="item in applyList" :key="item.applyCode" :label="item.applyCode" :value="item.applyCode" />
-              </el-select>
-            </el-form-item>
-          </el-col>
-        </el-row>
-        <el-row :gutter="20">
-          <el-col :span="12">
-            <el-form-item label="渚涘簲鍟�" prop="supplierId">
-              <el-select v-model="form.supplierId" placeholder="璇烽�夋嫨渚涘簲鍟�" style="width: 100%;" :disabled="isEdit">
-                <el-option v-for="item in supplierList" :key="item.id" :label="item.name" :value="item.id" />
-              </el-select>
-            </el-form-item>
-          </el-col>
-          <el-col :span="12">
-            <el-form-item label="浠樻鏃ユ湡" prop="paymentDate">
-              <el-date-picker v-model="form.paymentDate" type="date" placeholder="閫夋嫨鏃ユ湡" value-format="YYYY-MM-DD" style="width: 100%;" />
-            </el-form-item>
-          </el-col>
-        </el-row>
-        <el-row :gutter="20">
-          <el-col :span="12">
-            <el-form-item label="浠樻閲戦" prop="amount">
-              <el-input-number v-model="form.amount" :min="0" :precision="2" style="width: 100%;" />
-            </el-form-item>
-          </el-col>
-          <el-col :span="12">
-            <el-form-item label="浠樻鏂瑰紡" prop="paymentMethod">
-              <el-select v-model="form.paymentMethod" placeholder="璇烽�夋嫨浠樻鏂瑰紡" style="width: 100%;">
-                <el-option label="閾惰杞处" value="bank_transfer" />
-                <el-option label="鐜伴噾" value="cash" />
-                <el-option label="鏀エ" value="check" />
-                <el-option label="姹囩エ" value="draft" />
-              </el-select>
-            </el-form-item>
-          </el-col>
-        </el-row>
-        <el-row :gutter="20">
-          <el-col :span="12">
-            <el-form-item label="閾惰璐﹀彿" prop="bankAccount" v-if="form.paymentMethod === 'bank_transfer'">
-              <el-input v-model="form.bankAccount" placeholder="璇疯緭鍏ラ摱琛岃处鍙�" />
-            </el-form-item>
-          </el-col>
-          <el-col :span="12">
-            <el-form-item label="寮�鎴疯" prop="bankName" v-if="form.paymentMethod === 'bank_transfer'">
-              <el-input v-model="form.bankName" placeholder="璇疯緭鍏ュ紑鎴疯" />
-            </el-form-item>
-          </el-col>
-        </el-row>
-        <el-form-item label="澶囨敞" prop="remark">
-          <el-input v-model="form.remark" type="textarea" :rows="3" placeholder="璇疯緭鍏ュ娉�" />
-        </el-form-item>
-      </el-form>
-      <template #footer>
-        <el-button type="primary" @click="submitForm">纭畾</el-button>
-        <el-button @click="dialogVisible = false">鍙栨秷</el-button>
-      </template>
-    </FormDialog>
   </div>
 </template>
 
 <script setup>
-import { ref, reactive, onMounted, computed } from "vue";
+import { ref, reactive, computed, onMounted, getCurrentInstance } from "vue";
 import { ElMessage, ElMessageBox } from "element-plus";
-import FormDialog from "@/components/Dialog/FormDialog.vue";
+import { getOptions } from "@/api/procurementManagement/procurementLedger.js";
+import {
+  listPageAccountPurchasePayment,
+  deleteAccountPurchasePayment,
+} from "@/api/financialManagement/accountPurchasePayment.js";
 
 defineOptions({
   name: "浠樻鍗�",
 });
 
+const { proxy } = getCurrentInstance();
+const { checkout_payment } = proxy.useDict("checkout_payment");
+
 const filters = reactive({
-  paymentCode: "",
+  paymentNumber: "",
   supplierId: "",
   paymentMethod: "",
-  status: "",
+  dateRange: [],
 });
 
 const pagination = reactive({
@@ -164,200 +107,151 @@
 });
 
 const columns = [
-  { label: "浠樻鍗曞彿", prop: "paymentCode", width: "150" },
-  { label: "鍏宠仈鐢宠鍗�", prop: "applyCode", width: "150" },
+  { label: "浠樻鍗曞彿", prop: "paymentNumber", width: "150" },
+  { label: "鍏宠仈鐢宠鍗�", prop: "invoiceApplicationNo", width: "150" },
   { label: "渚涘簲鍟�", prop: "supplierName", width: "180" },
   { label: "浠樻鏃ユ湡", prop: "paymentDate", width: "120" },
-  { label: "浠樻閲戦", prop: "amount", slot: "amount" },
-  { label: "浠樻鏂瑰紡", prop: "paymentMethod", slot: "paymentMethod" },
-  { label: "鐘舵��", prop: "status", slot: "status" },
+  { label: "浠樻閲戦", prop: "amount", dataType: "slot", slot: "amount" },
+  { label: "浠樻鏂瑰紡", prop: "paymentMethod", dataType: "slot", slot: "paymentMethod", width: "120" },
   { label: "澶囨敞", prop: "remark", showOverflowTooltip: true },
-  { label: "鎿嶄綔", prop: "operation", slot: "operation", width: "220", fixed: "right" },
+  { label: "鎿嶄綔", prop: "operation", dataType: "slot", slot: "operation", width: "80", fixed: "right" },
 ];
 
 const dataList = ref([]);
-const dialogVisible = ref(false);
-const dialogTitle = ref("");
-const formRef = ref(null);
-const isEdit = ref(false);
-const currentId = ref(null);
+const tableLoading = ref(false);
+const supplierList = ref([]);
 
-const supplierList = [
-  { id: 1, name: "鍖椾含鍘熸潗鏂欎緵搴斿晢" },
-  { id: 2, name: "涓婃捣鐢靛瓙鍏冨櫒浠跺叕鍙�" },
-  { id: 3, name: "骞垮窞鍖呰鏉愭枡鍘�" },
-  { id: 4, name: "娣卞湷浜旈噾閰嶄欢鍏徃" },
-];
-
-const applyList = [
-  { applyCode: "FK2024001", supplierId: 1, amount: 5000 },
-  { applyCode: "FK2024002", supplierId: 2, amount: 8000 },
-  { applyCode: "FK2024003", supplierId: 3, amount: 3000 },
-];
-
-const form = reactive({
-  paymentCode: "",
-  applyCode: "",
-  supplierId: "",
-  paymentDate: "",
-  amount: 0,
-  paymentMethod: "bank_transfer",
-  bankAccount: "",
-  bankName: "",
-  remark: "",
-});
-
-const rules = {
-  applyCode: [{ required: true, message: "璇烽�夋嫨鍏宠仈鐢宠鍗�", trigger: "change" }],
-  supplierId: [{ required: true, message: "璇烽�夋嫨渚涘簲鍟�", trigger: "change" }],
-  paymentDate: [{ required: true, message: "璇烽�夋嫨浠樻鏃ユ湡", trigger: "change" }],
-  amount: [{ required: true, message: "璇疯緭鍏ヤ粯娆鹃噾棰�", trigger: "blur" }],
-  paymentMethod: [{ required: true, message: "璇烽�夋嫨浠樻鏂瑰紡", trigger: "change" }],
-};
-
-const mockData = [
-  { id: 1, paymentCode: "FKD2024001", applyCode: "FK2024001", supplierId: 1, supplierName: "鍖椾含鍘熸潗鏂欎緵搴斿晢", paymentDate: "2024-01-15", amount: 5000, paymentMethod: "bank_transfer", status: "completed", bankAccount: "6222021234567890123", bankName: "宸ュ晢閾惰", remark: "" },
-  { id: 2, paymentCode: "FKD2024002", applyCode: "FK2024002", supplierId: 2, supplierName: "涓婃捣鐢靛瓙鍏冨櫒浠跺叕鍙�", paymentDate: "2024-01-18", amount: 8000, paymentMethod: "bank_transfer", status: "pending", bankAccount: "6222029876543210987", bankName: "寤鸿閾惰", remark: "" },
-  { id: 3, paymentCode: "FKD2024003", applyCode: "FK2024003", supplierId: 3, supplierName: "骞垮窞鍖呰鏉愭枡鍘�", paymentDate: "2024-01-20", amount: 3000, paymentMethod: "cash", status: "completed", remark: "" },
-];
-
-const totalPaymentAmount = computed(() => {
-  return dataList.value.reduce((sum, item) => sum + Number(item.amount), 0);
-});
+const totalPaymentAmount = computed(() =>
+  dataList.value.reduce((sum, item) => sum + Number(item.amount ?? 0), 0)
+);
 
 const formatMoney = (value) => {
   if (value === undefined || value === null) return "0.00";
   return Number(value).toFixed(2).replace(/\B(?=(\d{3})+(?!\d))/g, ",");
 };
 
-const getPaymentMethodLabel = (method) => {
-  const map = {
-    bank_transfer: "閾惰杞处",
-    cash: "鐜伴噾",
-    check: "鏀エ",
-    draft: "姹囩エ",
-  };
-  return map[method] || method;
+const getPaymentMethodLabel = (value) => {
+  if (value === undefined || value === null || value === "") return "-";
+  const item = checkout_payment.value?.find((m) => String(m.value) === String(value));
+  return item?.label ?? value;
+};
+
+const normalizeTableRow = (row) => ({
+  ...row,
+  paymentNumber: row.paymentNumber ?? row.paymentCode,
+  invoiceApplicationNo: row.invoiceApplicationNo ?? row.applyCode ?? "",
+  amount: row.paymentAmount ?? row.amount,
+  bankAccountNum: row.bankAccountNum ?? row.bankAccount ?? "",
+  bankAccountName: row.bankAccountName ?? row.bankName ?? "",
+});
+
+const getSupplierList = () => {
+  getOptions().then((res) => {
+    if (res.code === 200) {
+      supplierList.value = res.data ?? [];
+    }
+  });
+};
+
+const appendFilterParams = (params) => {
+  if (filters.paymentNumber) {
+    params.paymentNumber = filters.paymentNumber;
+  }
+  if (filters.supplierId) {
+    params.supplierId = filters.supplierId;
+  }
+  if (filters.paymentMethod) {
+    params.paymentMethod = filters.paymentMethod;
+  }
+  if (filters.dateRange?.length === 2) {
+    params.startDate = filters.dateRange[0];
+    params.endDate = filters.dateRange[1];
+  }
+  return params;
+};
+
+const buildListParams = () =>
+  appendFilterParams({
+    current: pagination.currentPage,
+    size: pagination.pageSize,
+  });
+
+const buildExportParams = () => appendFilterParams({});
+
+const handleExport = () => {
+  proxy.download(
+    "/accountPurchasePayment/exportAccountPurchasePayment",
+    buildExportParams(),
+    `浠樻鍗昣${Date.now()}.xlsx`
+  );
 };
 
 const getTableData = () => {
-  let result = [...mockData];
-  if (filters.paymentCode) {
-    result = result.filter(item => item.paymentCode.includes(filters.paymentCode));
-  }
-  if (filters.supplierId) {
-    result = result.filter(item => item.supplierId === filters.supplierId);
-  }
-  if (filters.paymentMethod) {
-    result = result.filter(item => item.paymentMethod === filters.paymentMethod);
-  }
-  if (filters.status) {
-    result = result.filter(item => item.status === filters.status);
-  }
-  pagination.total = result.length;
-  dataList.value = result.slice((pagination.currentPage - 1) * pagination.pageSize, pagination.currentPage * pagination.pageSize);
+  tableLoading.value = true;
+  listPageAccountPurchasePayment(buildListParams())
+    .then((res) => {
+      if (res.code === 200) {
+        dataList.value = (res.data?.records ?? []).map(normalizeTableRow);
+        pagination.total = res.data?.total ?? 0;
+      } else {
+        dataList.value = [];
+        pagination.total = 0;
+        ElMessage.error(res.msg || "鏌ヨ澶辫触");
+      }
+    })
+    .catch(() => {
+      dataList.value = [];
+      pagination.total = 0;
+      ElMessage.error("鏌ヨ澶辫触");
+    })
+    .finally(() => {
+      tableLoading.value = false;
+    });
 };
 
-const resetFilters = () => {
-  filters.paymentCode = "";
-  filters.supplierId = "";
-  filters.paymentMethod = "";
-  filters.status = "";
+const onSearch = () => {
   pagination.currentPage = 1;
   getTableData();
 };
 
-const changePage = ({ current, size }) => {
-  pagination.currentPage = current;
-  pagination.pageSize = size;
+const resetFilters = () => {
+  filters.paymentNumber = "";
+  filters.supplierId = "";
+  filters.paymentMethod = "";
+  filters.dateRange = [];
+  pagination.currentPage = 1;
   getTableData();
 };
 
-const add = () => {
-  isEdit.value = false;
-  dialogTitle.value = "鏂板浠樻";
-  Object.assign(form, {
-    paymentCode: "FKD" + Date.now().toString().slice(-8),
-    applyCode: "",
-    supplierId: "",
-    paymentDate: new Date().toISOString().split('T')[0],
-    amount: 0,
-    paymentMethod: "bank_transfer",
-    bankAccount: "",
-    bankName: "",
-    remark: "",
-  });
-  dialogVisible.value = true;
+const changePage = ({ page, limit }) => {
+  pagination.currentPage = page;
+  pagination.pageSize = limit;
+  getTableData();
 };
 
-const edit = (row) => {
-  isEdit.value = true;
-  currentId.value = row.id;
-  dialogTitle.value = "缂栬緫浠樻";
-  Object.assign(form, row);
-  dialogVisible.value = true;
-};
-
-const view = (row) => {
-  ElMessage.info(`鏌ョ湅浠樻鍗�: ${row.paymentCode}`);
-};
-
-const handleComplete = (row) => {
-  ElMessageBox.confirm("纭璇ヤ粯娆惧崟宸插畬鎴愬悧锛�", "鎻愮ず", {
-    confirmButtonText: "纭",
-    cancelButtonText: "鍙栨秷",
-    type: "info",
-  }).then(() => {
-    const index = mockData.findIndex(item => item.id === row.id);
-    if (index !== -1) {
-      mockData[index].status = "completed";
-    }
-    ElMessage.success("浠樻瀹屾垚");
-    getTableData();
-  });
-};
-
-const handleCancel = (row) => {
-  ElMessageBox.confirm("纭鍙栨秷璇ヤ粯娆惧崟鍚楋紵", "鎻愮ず", {
-    confirmButtonText: "纭",
+const handleDelete = (row) => {
+  ElMessageBox.confirm(`纭鍒犻櫎浠樻鍗曘��${row.paymentNumber}銆嶅悧锛焋, "鎻愮ず", {
+    confirmButtonText: "纭畾",
     cancelButtonText: "鍙栨秷",
     type: "warning",
   }).then(() => {
-    const index = mockData.findIndex(item => item.id === row.id);
-    if (index !== -1) {
-      mockData[index].status = "cancelled";
-    }
-    ElMessage.success("宸插彇娑�");
-    getTableData();
-  });
-};
-
-const handleOut = () => {
-  ElMessage.success("瀵煎嚭鎴愬姛");
-};
-
-const submitForm = () => {
-  formRef.value.validate((valid) => {
-    if (valid) {
-      const supplier = supplierList.find(item => item.id === form.supplierId);
-      if (isEdit.value) {
-        const index = mockData.findIndex(item => item.id === currentId.value);
-        if (index !== -1) {
-          mockData[index] = { ...mockData[index], ...form, supplierName: supplier?.name };
+    deleteAccountPurchasePayment([row.id])
+      .then((res) => {
+        if (res.code === 200) {
+          ElMessage.success("鍒犻櫎鎴愬姛");
+          getTableData();
+        } else {
+          ElMessage.error(res.msg || "鍒犻櫎澶辫触");
         }
-        ElMessage.success("缂栬緫鎴愬姛");
-      } else {
-        const newId = mockData.length > 0 ? Math.max(...mockData.map(item => item.id)) + 1 : 1;
-        mockData.push({ id: newId, ...form, supplierName: supplier?.name, status: "pending" });
-        ElMessage.success("鏂板鎴愬姛");
-      }
-      dialogVisible.value = false;
-      getTableData();
-    }
+      })
+      .catch(() => {
+        ElMessage.error("鍒犻櫎澶辫触");
+      });
   });
 };
 
 onMounted(() => {
+  getSupplierList();
   getTableData();
 });
 </script>
diff --git a/src/views/financialManagement/payable/paymentApply.vue b/src/views/financialManagement/payable/paymentApply.vue
index fb23db3..3937e96 100644
--- a/src/views/financialManagement/payable/paymentApply.vue
+++ b/src/views/financialManagement/payable/paymentApply.vue
@@ -2,23 +2,40 @@
   <div class="app-container">
     <el-form :model="filters" :inline="true">
       <el-form-item label="鐢宠鍗曞彿:">
-        <el-input v-model="filters.applyCode" placeholder="璇疯緭鍏ョ敵璇峰崟鍙�" clearable style="width: 200px;" />
+        <el-input v-model="filters.invoiceApplicationNo" placeholder="璇疯緭鍏ョ敵璇峰崟鍙�" clearable style="width: 200px;" />
       </el-form-item>
       <el-form-item label="渚涘簲鍟�:">
-        <el-select v-model="filters.supplierId" placeholder="璇烽�夋嫨渚涘簲鍟�" clearable style="width: 200px;">
-          <el-option v-for="item in supplierList" :key="item.id" :label="item.name" :value="item.id" />
+        <el-select v-model="filters.supplierId" placeholder="璇烽�夋嫨渚涘簲鍟�" clearable filterable style="width: 200px;">
+          <el-option
+            v-for="item in supplierList"
+            :key="item.id"
+            :label="item.supplierName"
+            :value="item.id"
+          />
         </el-select>
       </el-form-item>
-      <el-form-item label="鐘舵��:">
+      <el-form-item label="瀹℃牳鐘舵��:">
         <el-select v-model="filters.status" placeholder="璇烽�夋嫨鐘舵��" clearable style="width: 150px;">
-          <el-option label="寰呭鎵�" value="pending" />
-          <el-option label="宸插鎵�" value="approved" />
-          <el-option label="宸查┏鍥�" value="rejected" />
-          <el-option label="宸蹭粯娆�" value="paid" />
+          <el-option label="寰呭鏍�" :value="0" />
+          <el-option label="瀹℃牳閫氳繃" :value="1" />
+          <el-option label="瀹℃牳涓嶉�氳繃" :value="2" />
         </el-select>
+      </el-form-item>
+      <el-form-item label="鐢宠鏃ユ湡:">
+        <el-date-picker
+          v-model="filters.dateRange"
+          type="daterange"
+          value-format="YYYY-MM-DD"
+          format="YYYY-MM-DD"
+          range-separator="鑷�"
+          start-placeholder="寮�濮嬫棩鏈�"
+          end-placeholder="缁撴潫鏃ユ湡"
+          clearable
+          style="width: 240px;"
+        />
       </el-form-item>
       <el-form-item>
-        <el-button type="primary" @click="getTableData">鎼滅储</el-button>
+        <el-button type="primary" @click="onSearch">鎼滅储</el-button>
         <el-button @click="resetFilters">閲嶇疆</el-button>
       </el-form-item>
     </el-form>
@@ -27,20 +44,19 @@
         <div></div>
         <div>
           <el-button type="primary" @click="add" icon="Plus">鏂板鐢宠</el-button>
-          <el-button @click="handleBatchApply" icon="Document" :disabled="selectedRows.length === 0">鎵归噺鐢宠</el-button>
+          <el-button @click="handleExport" icon="Download">瀵煎嚭</el-button>
         </div>
       </div>
       <PIMTable
         rowKey="id"
-        isSelection
         :column="columns"
         :tableData="dataList"
+        :tableLoading="tableLoading"
         :page="{
           current: pagination.currentPage,
           size: pagination.pageSize,
           total: pagination.total,
         }"
-        @selection-change="handleSelectionChange"
         @pagination="changePage"
       >
         <template #amount="{ row }">
@@ -54,90 +70,291 @@
         </template>
         <template #operation="{ row }">
           <el-button type="primary" link @click="view(row)">鏌ョ湅</el-button>
-          <el-button type="primary" link @click="edit(row)" v-if="row.status === 'pending'">缂栬緫</el-button>
-          <el-button type="success" link @click="handleAudit(row)" v-if="row.status === 'pending'">瀹℃壒</el-button>
+          <el-button type="primary" link @click="edit(row)" v-if="isPendingStatus(row.status)">缂栬緫</el-button>
+          <el-button type="success" link @click="handleAudit(row)" v-if="isPendingStatus(row.status)">瀹℃牳</el-button>
+          <el-button type="warning" link @click="openPaymentDialog(row)" v-if="isApprovedStatus(row.status)">浠樻</el-button>
+          <el-button type="danger" link @click="handleDelete(row)" v-if="isPendingStatus(row.status)">鍒犻櫎</el-button>
         </template>
       </PIMTable>
     </div>
 
-    <FormDialog :title="dialogTitle" v-model="dialogVisible" width="800px" @confirm="submitForm" @cancel="dialogVisible = false">
+    <FormDialog
+      :title="dialogTitle"
+      v-model="dialogVisible"
+      width="800px"
+      :operation-type="isView ? 'detail' : ''"
+      @confirm="submitForm"
+      @cancel="closeDialog"
+    >
       <el-form :model="form" :rules="rules" ref="formRef" label-width="120px">
+        <el-row v-if="isView" :gutter="20">
+          <el-col :span="12">
+            <el-form-item label="瀹℃牳鐘舵��">
+              <el-tag :type="getStatusType(form.status)">{{ getStatusLabel(form.status) }}</el-tag>
+            </el-form-item>
+          </el-col>
+        </el-row>
         <el-row :gutter="20">
           <el-col :span="12">
-            <el-form-item label="鐢宠鍗曞彿" prop="applyCode">
-              <el-input v-model="form.applyCode" placeholder="绯荤粺鑷姩鐢熸垚" disabled />
+            <el-form-item label="鐢宠鍗曞彿" prop="invoiceApplicationNo">
+              <el-input v-model="form.invoiceApplicationNo" placeholder="绯荤粺鑷姩鐢熸垚" disabled />
             </el-form-item>
           </el-col>
           <el-col :span="12">
             <el-form-item label="渚涘簲鍟�" prop="supplierId">
-              <el-select v-model="form.supplierId" placeholder="璇烽�夋嫨渚涘簲鍟�" style="width: 100%;" :disabled="isEdit">
-                <el-option v-for="item in supplierList" :key="item.id" :label="item.name" :value="item.id" />
+              <el-select
+                v-model="form.supplierId"
+                placeholder="璇烽�夋嫨渚涘簲鍟�"
+                style="width: 100%;"
+                filterable
+                :disabled="isEdit || isView"
+                @change="handleSupplierChange"
+              >
+                <el-option
+                  v-for="item in supplierList"
+                  :key="item.id"
+                  :label="item.supplierName"
+                  :value="item.id"
+                />
               </el-select>
             </el-form-item>
           </el-col>
         </el-row>
         <el-row :gutter="20">
           <el-col :span="12">
-            <el-form-item label="浠樻閲戦" prop="amount">
-              <el-input-number v-model="form.amount" :min="0" :precision="2" style="width: 100%;" />
+            <el-form-item label="鍏宠仈鍏ュ簱鍗�" prop="stockInRecordIds">
+              <el-input
+                :model-value="inboundBatchDisplayText"
+                placeholder="璇峰厛閫夋嫨渚涘簲鍟�"
+                readonly
+                :disabled="!form.supplierId || isEdit || isView"
+                class="inbound-batch-input"
+                @click="handleInboundInputClick"
+              >
+                <template v-if="!isEdit && !isView" #append>
+                  <el-button
+                    :disabled="!form.supplierId"
+                    :loading="inboundBatchLoading"
+                    @click.stop="openInboundSelectDialog"
+                  >
+                    閫夋嫨
+                  </el-button>
+                </template>
+              </el-input>
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="鐢宠鏃ユ湡" prop="applyDate">
+              <el-date-picker
+                v-model="form.applyDate"
+                type="date"
+                placeholder="閫夋嫨鏃ユ湡"
+                value-format="YYYY-MM-DD"
+                style="width: 100%;"
+                :disabled="isView"
+              />
+            </el-form-item>
+          </el-col>
+        </el-row>
+        <el-row :gutter="20">
+          <el-col :span="12">
+            <el-form-item label="浠樻閲戦" prop="paymentAmount">
+              <el-input-number
+                v-model="form.paymentAmount"
+                :min="0"
+                :precision="2"
+                style="width: 100%;"
+                :disabled="isView"
+                placeholder="鏍规嵁鍏ュ簱鍗曡嚜鍔ㄦ眹鎬伙紝鍙慨鏀�"
+              />
             </el-form-item>
           </el-col>
           <el-col :span="12">
             <el-form-item label="浠樻鏂瑰紡" prop="paymentMethod">
-              <el-select v-model="form.paymentMethod" placeholder="璇烽�夋嫨浠樻鏂瑰紡" style="width: 100%;">
-                <el-option label="閾惰杞处" value="bank_transfer" />
-                <el-option label="鐜伴噾" value="cash" />
-                <el-option label="鏀エ" value="check" />
-                <el-option label="姹囩エ" value="draft" />
+              <el-select
+                v-model="form.paymentMethod"
+                placeholder="璇烽�夋嫨浠樻鏂瑰紡"
+                style="width: 100%;"
+                :disabled="isView"
+              >
+                <el-option
+                  v-for="item in checkout_payment"
+                  :key="item.value"
+                  :label="item.label"
+                  :value="item.value"
+                />
               </el-select>
+            </el-form-item>
+          </el-col>
+        </el-row>
+        <el-form-item label="浠樻浜嬬敱" prop="paymentContent">
+          <el-input
+            v-model="form.paymentContent"
+            type="textarea"
+            :rows="3"
+            placeholder="璇疯緭鍏ヤ粯娆句簨鐢�"
+            :disabled="isView"
+          />
+        </el-form-item>
+        <el-form-item label="澶囨敞" prop="remark">
+          <el-input v-model="form.remark" type="textarea" :rows="2" placeholder="璇疯緭鍏ュ娉�" :disabled="isView" />
+        </el-form-item>
+      </el-form>
+      <template v-if="!isView" #footer>
+        <el-button type="primary" :loading="submitLoading" @click="submitForm">纭畾</el-button>
+        <el-button @click="closeDialog">鍙栨秷</el-button>
+      </template>
+    </FormDialog>
+
+    <FormDialog
+      title="浠樻"
+      v-model="paymentDialogVisible"
+      width="800px"
+      @confirm="submitPayment"
+      @cancel="paymentDialogVisible = false"
+    >
+      <el-form :model="paymentForm" :rules="paymentRules" ref="paymentFormRef" label-width="120px">
+        <el-row :gutter="20">
+          <el-col :span="12">
+            <el-form-item label="浠樻鍗曞彿" prop="paymentNumber">
+              <el-input v-model="paymentForm.paymentNumber" placeholder="绯荤粺鑷姩鐢熸垚" disabled />
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="鍏宠仈鐢宠鍗�" prop="invoiceApplicationNo">
+              <el-input v-model="paymentForm.invoiceApplicationNo" disabled />
             </el-form-item>
           </el-col>
         </el-row>
         <el-row :gutter="20">
           <el-col :span="12">
-            <el-form-item label="鐢宠鏃ユ湡" prop="applyDate">
-              <el-date-picker v-model="form.applyDate" type="date" placeholder="閫夋嫨鏃ユ湡" value-format="YYYY-MM-DD" style="width: 100%;" />
+            <el-form-item label="渚涘簲鍟�">
+              <el-input v-model="paymentForm.supplierName" disabled />
             </el-form-item>
           </el-col>
           <el-col :span="12">
-            <el-form-item label="鏈熸湜浠樻鏃ユ湡" prop="expectedDate">
-              <el-date-picker v-model="form.expectedDate" type="date" placeholder="閫夋嫨鏃ユ湡" value-format="YYYY-MM-DD" style="width: 100%;" />
+            <el-form-item label="浠樻鏃ユ湡" prop="paymentDate">
+              <el-date-picker
+                v-model="paymentForm.paymentDate"
+                type="date"
+                placeholder="閫夋嫨鏃ユ湡"
+                value-format="YYYY-MM-DD"
+                style="width: 100%;"
+              />
             </el-form-item>
           </el-col>
         </el-row>
-        <el-form-item label="鍏宠仈鍏ュ簱鍗�" prop="relatedDocs">
-          <el-select v-model="form.relatedDocs" multiple placeholder="璇烽�夋嫨鍏宠仈鍏ュ簱鍗�" style="width: 100%;">
-            <el-option v-for="item in inList" :key="item.inCode" :label="item.inCode" :value="item.inCode" />
-          </el-select>
-        </el-form-item>
-        <el-form-item label="浠樻浜嬬敱" prop="reason">
-          <el-input v-model="form.reason" type="textarea" :rows="3" placeholder="璇疯緭鍏ヤ粯娆句簨鐢�" />
-        </el-form-item>
+        <el-row :gutter="20">
+          <el-col :span="12">
+            <el-form-item label="浠樻閲戦" prop="paymentAmount">
+              <el-input-number
+                v-model="paymentForm.paymentAmount"
+                :min="0"
+                :precision="2"
+                style="width: 100%;"
+              />
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="浠樻鏂瑰紡" prop="paymentMethod">
+              <el-select v-model="paymentForm.paymentMethod" placeholder="璇烽�夋嫨浠樻鏂瑰紡" style="width: 100%;">
+                <el-option
+                  v-for="item in checkout_payment"
+                  :key="item.value"
+                  :label="item.label"
+                  :value="item.value"
+                />
+              </el-select>
+            </el-form-item>
+          </el-col>
+        </el-row>
+        <el-row v-if="isBankTransferPayment(paymentForm.paymentMethod)" :gutter="20">
+          <el-col :span="12">
+            <el-form-item label="閾惰璐﹀彿" prop="bankAccount">
+              <el-input v-model="paymentForm.bankAccount" placeholder="閾惰璐﹀彿" />
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="寮�鎴疯" prop="bankName">
+              <el-input v-model="paymentForm.bankName" placeholder="寮�鎴疯" />
+            </el-form-item>
+          </el-col>
+        </el-row>
         <el-form-item label="澶囨敞" prop="remark">
-          <el-input v-model="form.remark" type="textarea" :rows="2" placeholder="璇疯緭鍏ュ娉�" />
+          <el-input v-model="paymentForm.remark" type="textarea" :rows="3" placeholder="璇疯緭鍏ュ娉�" />
         </el-form-item>
       </el-form>
       <template #footer>
-        <el-button type="primary" @click="submitForm">纭畾</el-button>
-        <el-button @click="dialogVisible = false">鍙栨秷</el-button>
+        <el-button type="primary" :loading="paymentSubmitLoading" @click="submitPayment">纭畾</el-button>
+        <el-button @click="paymentDialogVisible = false">鍙栨秷</el-button>
       </template>
     </FormDialog>
+
+    <el-dialog
+      v-model="inboundSelectVisible"
+      title="閫夋嫨鍏ュ簱鍗曞彿"
+      width="1100px"
+      append-to-body
+      destroy-on-close
+      :close-on-click-modal="false"
+      @closed="handleInboundDialogClosed"
+    >
+      <el-table
+        ref="inboundTableRef"
+        v-loading="inboundBatchLoading"
+        :data="inboundBatchList"
+        row-key="id"
+        border
+        stripe
+        max-height="480"
+        @selection-change="handleInboundDialogSelectionChange"
+      >
+        <el-table-column type="selection" width="55" align="center" />
+        <el-table-column prop="inboundBatches" label="鍏ュ簱鍗曞彿" min-width="140" show-overflow-tooltip />
+        <el-table-column prop="supplierName" label="渚涘簲鍟�" min-width="120" show-overflow-tooltip />
+        <el-table-column prop="productName" label="浜у搧鍚嶇О" min-width="120" show-overflow-tooltip />
+        <el-table-column prop="specificationModel" label="瑙勬牸鍨嬪彿" min-width="140" show-overflow-tooltip />
+        <el-table-column prop="purchaseContractNumber" label="閲囪喘璁㈠崟鍙�" min-width="140" show-overflow-tooltip />
+        <el-table-column prop="inboundDate" label="鍏ュ簱鏃ユ湡" width="110" align="center" />
+        <el-table-column prop="inboundAmount" label="鍏ュ簱閲戦(鍚◣)" width="120" align="right">
+          <template #default="{ row }">楼{{ formatMoney(getInboundRowTaxInclusiveAmount(row)) }}</template>
+        </el-table-column>
+      </el-table>
+      <template #footer>
+        <el-button type="primary" @click="confirmInboundSelection">纭畾</el-button>
+        <el-button @click="inboundSelectVisible = false">鍙栨秷</el-button>
+      </template>
+    </el-dialog>
   </div>
 </template>
 
 <script setup>
-import { ref, reactive, onMounted } from "vue";
+import { ref, reactive, computed, onMounted, nextTick, getCurrentInstance } from "vue";
 import { ElMessage, ElMessageBox } from "element-plus";
 import FormDialog from "@/components/Dialog/FormDialog.vue";
+import { getOptions } from "@/api/procurementManagement/procurementLedger.js";
+import {
+  getInboundBatchesBySupplier,
+  addAccountPaymentApplication,
+  listPageAccountPaymentApplication,
+  updateAccountPaymentApplication,
+  auditAccountPaymentApplication,
+  deleteAccountPaymentApplication,
+} from "@/api/financialManagement/accountPaymentApplication.js";
+import { addAccountPurchasePayment } from "@/api/financialManagement/accountPurchasePayment.js";
 
 defineOptions({
   name: "浠樻鐢宠",
 });
 
+const { proxy } = getCurrentInstance();
+const { checkout_payment } = proxy.useDict("checkout_payment");
+
 const filters = reactive({
-  applyCode: "",
+  invoiceApplicationNo: "",
   supplierId: "",
   status: "",
+  dateRange: [],
 });
 
 const pagination = reactive({
@@ -149,199 +366,634 @@
 const columns = [
   { label: "鐢宠鍗曞彿", prop: "applyCode", width: "150" },
   { label: "渚涘簲鍟�", prop: "supplierName", width: "180" },
-  { label: "浠樻閲戦", prop: "amount", slot: "amount" },
-  { label: "浠樻鏂瑰紡", prop: "paymentMethod", slot: "paymentMethod" },
+  { label: "浠樻閲戦", prop: "amount", dataType: "slot", slot: "amount" },
+  { label: "浠樻鏂瑰紡", prop: "paymentMethod", dataType: "slot", slot: "paymentMethod", width: "120" },
   { label: "鐢宠鏃ユ湡", prop: "applyDate", width: "120" },
-  { label: "鏈熸湜浠樻鏃�", prop: "expectedDate", width: "120" },
-  { label: "鐘舵��", prop: "status", slot: "status" },
-  { label: "鎿嶄綔", prop: "operation", slot: "operation", width: "200", fixed: "right" },
+  { label: "鐘舵��", prop: "status", dataType: "slot", slot: "status", width: "100" },
+  { label: "鎿嶄綔", prop: "operation", dataType: "slot", slot: "operation", width: "260", fixed: "right" },
 ];
 
 const dataList = ref([]);
-const selectedRows = ref([]);
+const tableLoading = ref(false);
 const dialogVisible = ref(false);
 const dialogTitle = ref("");
 const formRef = ref(null);
 const isEdit = ref(false);
+const isView = ref(false);
+const submitLoading = ref(false);
 const currentId = ref(null);
+const supplierList = ref([]);
 
-const supplierList = [
-  { id: 1, name: "鍖椾含鍘熸潗鏂欎緵搴斿晢" },
-  { id: 2, name: "涓婃捣鐢靛瓙鍏冨櫒浠跺叕鍙�" },
-  { id: 3, name: "骞垮窞鍖呰鏉愭枡鍘�" },
-  { id: 4, name: "娣卞湷浜旈噾閰嶄欢鍏徃" },
-];
+const inboundBatchList = ref([]);
+const inboundBatchOptions = ref([]);
+const inboundBatchLoading = ref(false);
+const inboundSelectVisible = ref(false);
+const inboundTableRef = ref(null);
+const dialogInboundSelection = ref([]);
 
-const inList = [
-  { inCode: "RK2024001", supplierId: 1 },
-  { inCode: "RK2024002", supplierId: 2 },
-  { inCode: "RK2024003", supplierId: 3 },
-];
+const paymentDialogVisible = ref(false);
+const paymentFormRef = ref(null);
+const paymentSubmitLoading = ref(false);
+
+const paymentForm = reactive({
+  paymentNumber: "",
+  invoiceApplicationNo: "",
+  supplierName: "",
+  supplierId: "",
+  accountPaymentApplicationId: null,
+  paymentDate: "",
+  paymentAmount: 0,
+  paymentMethod: "",
+  bankAccount: "",
+  bankName: "",
+  remark: "",
+});
+
+const paymentRules = {
+  paymentDate: [{ required: true, message: "璇烽�夋嫨浠樻鏃ユ湡", trigger: "change" }],
+  paymentAmount: [{ required: true, message: "璇疯緭鍏ヤ粯娆鹃噾棰�", trigger: "blur" }],
+  paymentMethod: [{ required: true, message: "璇烽�夋嫨浠樻鏂瑰紡", trigger: "change" }],
+};
+
+const STATUS_LABEL_MAP = { 0: "寰呭鏍�", 1: "瀹℃牳閫氳繃", 2: "瀹℃牳涓嶉�氳繃" };
+const STATUS_TYPE_MAP = { 0: "warning", 1: "success", 2: "danger" };
 
 const form = reactive({
-  applyCode: "",
+  invoiceApplicationNo: "",
   supplierId: "",
-  amount: 0,
-  paymentMethod: "bank_transfer",
+  paymentAmount: 0,
+  paymentMethod: "",
   applyDate: "",
-  expectedDate: "",
-  relatedDocs: [],
-  reason: "",
+  paymentContent: "",
   remark: "",
+  stockInRecordIds: [],
+  inboundBatches: "",
+  status: 0,
 });
 
 const rules = {
   supplierId: [{ required: true, message: "璇烽�夋嫨渚涘簲鍟�", trigger: "change" }],
-  amount: [{ required: true, message: "璇疯緭鍏ヤ粯娆鹃噾棰�", trigger: "blur" }],
+  stockInRecordIds: [{ required: true, type: "array", min: 1, message: "璇烽�夋嫨鍏宠仈鍏ュ簱鍗�", trigger: "change" }],
+  paymentAmount: [{ required: true, message: "璇疯緭鍏ヤ粯娆鹃噾棰�", trigger: "blur" }],
   paymentMethod: [{ required: true, message: "璇烽�夋嫨浠樻鏂瑰紡", trigger: "change" }],
   applyDate: [{ required: true, message: "璇烽�夋嫨鐢宠鏃ユ湡", trigger: "change" }],
-  expectedDate: [{ required: true, message: "璇烽�夋嫨鏈熸湜浠樻鏃ユ湡", trigger: "change" }],
 };
-
-const mockData = [
-  { id: 1, applyCode: "FK2024001", supplierId: 1, supplierName: "鍖椾含鍘熸潗鏂欎緵搴斿晢", amount: 5000, paymentMethod: "bank_transfer", applyDate: "2024-01-12", expectedDate: "2024-01-15", status: "pending", relatedDocs: ["RK2024001"], reason: "鏀粯鍘熸潗鏂欒揣娆�", remark: "" },
-  { id: 2, applyCode: "FK2024002", supplierId: 2, supplierName: "涓婃捣鐢靛瓙鍏冨櫒浠跺叕鍙�", amount: 8000, paymentMethod: "bank_transfer", applyDate: "2024-01-14", expectedDate: "2024-01-18", status: "approved", relatedDocs: ["RK2024002"], reason: "鏀粯鐢靛瓙鍏冨櫒浠惰揣娆�", remark: "" },
-  { id: 3, applyCode: "FK2024003", supplierId: 3, supplierName: "骞垮窞鍖呰鏉愭枡鍘�", amount: 3000, paymentMethod: "cash", applyDate: "2024-01-16", expectedDate: "2024-01-20", status: "paid", relatedDocs: ["RK2024003"], reason: "鏀粯鍖呰鏉愭枡璐ф", remark: "" },
-];
 
 const formatMoney = (value) => {
   if (value === undefined || value === null) return "0.00";
   return Number(value).toFixed(2).replace(/\B(?=(\d{3})+(?!\d))/g, ",");
 };
 
-const getPaymentMethodLabel = (method) => {
-  const map = {
-    bank_transfer: "閾惰杞处",
-    cash: "鐜伴噾",
-    check: "鏀エ",
-    draft: "姹囩エ",
+const normalizeStatus = (status) => {
+  if (status === undefined || status === null || status === "") return 0;
+  const num = Number(status);
+  return Number.isNaN(num) ? 0 : num;
+};
+
+const isPendingStatus = (status) => normalizeStatus(status) === 0;
+
+const isApprovedStatus = (status) => normalizeStatus(status) === 1;
+
+const isBankTransferPayment = (method) => {
+  if (method === undefined || method === null || method === "") return false;
+  const item = checkout_payment.value?.find((m) => String(m.value) === String(method));
+  if (item?.label?.includes("閾惰")) return true;
+  return String(method) === "bank_transfer" || String(method).toLowerCase().includes("bank");
+};
+
+const getStatusLabel = (status) => STATUS_LABEL_MAP[normalizeStatus(status)] ?? "寰呭鏍�";
+
+const getStatusType = (status) => STATUS_TYPE_MAP[normalizeStatus(status)] ?? "warning";
+
+const getPaymentMethodLabel = (value) => {
+  if (value === undefined || value === null || value === "") return "-";
+  const item = checkout_payment.value?.find((m) => String(m.value) === String(value));
+  return item?.label ?? value;
+};
+
+const getDefaultPaymentMethod = () => checkout_payment.value?.[0]?.value ?? "";
+
+const parseStockInRecordIds = (value) => {
+  if (!value) return [];
+  if (Array.isArray(value)) return value;
+  return String(value)
+    .split(/[,锛宂/)
+    .map((s) => s.trim())
+    .filter(Boolean)
+    .map((s) => (/^\d+$/.test(s) ? Number(s) : s));
+};
+
+const formatInboundBatches = (value) => {
+  if (value === undefined || value === null || value === "") return "";
+  if (Array.isArray(value)) return value.filter(Boolean).join("銆�");
+  return String(value)
+    .split(/[,锛宂/)
+    .map((s) => s.trim())
+    .filter(Boolean)
+    .join("銆�");
+};
+
+const isSameInboundId = (a, b) => String(a) === String(b);
+
+const getInboundRowId = (row) => row?.id ?? row?.stockInRecordId;
+
+const getInboundRowTaxInclusiveAmount = (row) =>
+  Number(row?.inboundAmount ?? row?.taxInclusivePrice ?? row?.totalAmount ?? row?.amount ?? 0);
+
+const normalizeInboundBatchOptions = (data) => {
+  const list = Array.isArray(data) ? data : [];
+  return list.map((item, index) => {
+    const label =
+      item.inboundBatches ?? item.batchNo ?? item.inboundNo ?? `鍏ュ簱鍗�${index + 1}`;
+    const value = item.id ?? item.stockInRecordId ?? label;
+    return {
+      label: String(label),
+      value,
+      inboundAmount: getInboundRowTaxInclusiveAmount(item),
+    };
+  });
+};
+
+const syncPaymentAmount = () => {
+  const selected = form.stockInRecordIds || [];
+  let sum = inboundBatchOptions.value
+    .filter((opt) => selected.some((id) => isSameInboundId(id, opt.value)))
+    .reduce((acc, opt) => acc + (Number(opt.inboundAmount) || 0), 0);
+
+  if (sum <= 0 && selected.length) {
+    sum = inboundBatchList.value
+      .filter((row) => selected.some((id) => isSameInboundId(id, getInboundRowId(row))))
+      .reduce((acc, row) => acc + getInboundRowTaxInclusiveAmount(row), 0);
+  }
+
+  form.paymentAmount = sum > 0 ? Number(sum.toFixed(2)) : 0;
+};
+
+const inboundBatchDisplayText = computed(() => {
+  if (form.inboundBatches) return form.inboundBatches;
+  const ids = form.stockInRecordIds || [];
+  if (!ids.length) return "";
+  const labels = inboundBatchOptions.value
+    .filter((opt) => ids.some((id) => isSameInboundId(id, opt.value)))
+    .map((opt) => opt.label);
+  if (labels.length) return labels.join("銆�");
+  return ids.join("銆�");
+});
+
+const normalizeTableRow = (row) => ({
+  ...row,
+  applyCode: row.invoiceApplicationNo ?? row.applyCode,
+  amount: row.paymentAmount ?? row.amount,
+  reason: row.paymentContent ?? row.reason,
+  status: normalizeStatus(row.status),
+  stockInRecordIds: row.stockInRecordIds ?? "",
+  inboundBatches: formatInboundBatches(row.inboundBatches),
+});
+
+const fillFormFromRow = (row) => {
+  const stockInRecordIds = parseStockInRecordIds(row.stockInRecordIds);
+  Object.assign(form, {
+    invoiceApplicationNo: row.invoiceApplicationNo ?? row.applyCode ?? "",
+    supplierId: row.supplierId,
+    paymentAmount: Number(row.paymentAmount ?? row.amount ?? 0),
+    paymentMethod: row.paymentMethod ?? getDefaultPaymentMethod(),
+    applyDate: row.applyDate ?? "",
+    paymentContent: row.paymentContent ?? row.reason ?? "",
+    remark: row.remark ?? "",
+    stockInRecordIds,
+    inboundBatches: formatInboundBatches(row.inboundBatches),
+    status: normalizeStatus(row.status),
+  });
+};
+
+const buildPayloadFromRow = (row, statusOverride) => ({
+  id: row.id,
+  supplierId: row.supplierId,
+  stockInRecordIds:
+    typeof row.stockInRecordIds === "string"
+      ? row.stockInRecordIds
+      : (row.stockInRecordIds || []).join(","),
+  invoiceApplicationNo: row.invoiceApplicationNo ?? row.applyCode ?? "",
+  paymentMethod: row.paymentMethod,
+  paymentContent: row.paymentContent ?? row.reason ?? "",
+  applyDate: row.applyDate,
+  remark: row.remark ?? "",
+  status: statusOverride !== undefined ? statusOverride : normalizeStatus(row.status),
+  paymentAmount: Number(row.paymentAmount ?? row.amount ?? 0),
+});
+
+const buildSubmitPayload = (forUpdate = false) => {
+  const payload = {
+    supplierId: form.supplierId,
+    stockInRecordIds: (form.stockInRecordIds || []).join(","),
+    invoiceApplicationNo: form.invoiceApplicationNo || "",
+    paymentMethod: form.paymentMethod,
+    paymentContent: form.paymentContent || "",
+    applyDate: form.applyDate,
+    remark: form.remark || "",
+    status: 0,
+    paymentAmount: form.paymentAmount,
   };
-  return map[method] || method;
+  if (forUpdate) {
+    payload.id = currentId.value;
+  }
+  return payload;
 };
 
-const getStatusLabel = (status) => {
-  const map = { pending: "寰呭鎵�", approved: "宸插鎵�", rejected: "宸查┏鍥�", paid: "宸蹭粯娆�" };
-  return map[status] || status;
+const getSupplierList = () => {
+  getOptions().then((res) => {
+    if (res.code === 200) {
+      supplierList.value = res.data ?? [];
+    }
+  });
 };
 
-const getStatusType = (status) => {
-  const map = { pending: "warning", approved: "success", rejected: "danger", paid: "primary" };
-  return map[status] || "";
+const appendFilterParams = (params) => {
+  if (filters.invoiceApplicationNo) {
+    params.invoiceApplicationNo = filters.invoiceApplicationNo;
+  }
+  if (filters.supplierId) {
+    params.supplierId = filters.supplierId;
+  }
+  if (filters.status !== "" && filters.status != null) {
+    params.status = filters.status;
+  }
+  if (filters.dateRange?.length === 2) {
+    params.startDate = filters.dateRange[0];
+    params.endDate = filters.dateRange[1];
+  }
+  return params;
+};
+
+const buildListParams = () =>
+  appendFilterParams({
+    current: pagination.currentPage,
+    size: pagination.pageSize,
+  });
+
+const buildExportParams = () => appendFilterParams({});
+
+const handleExport = () => {
+  proxy.download(
+    "/accountPaymentApplication/exportAccountPaymentApplication",
+    buildExportParams(),
+    `浠樻鐢宠_${Date.now()}.xlsx`
+  );
 };
 
 const getTableData = () => {
-  let result = [...mockData];
-  if (filters.applyCode) {
-    result = result.filter(item => item.applyCode.includes(filters.applyCode));
-  }
-  if (filters.supplierId) {
-    result = result.filter(item => item.supplierId === filters.supplierId);
-  }
-  if (filters.status) {
-    result = result.filter(item => item.status === filters.status);
-  }
-  pagination.total = result.length;
-  dataList.value = result.slice((pagination.currentPage - 1) * pagination.pageSize, pagination.currentPage * pagination.pageSize);
+  tableLoading.value = true;
+  listPageAccountPaymentApplication(buildListParams())
+    .then((res) => {
+      if (res.code === 200) {
+        dataList.value = (res.data?.records ?? []).map(normalizeTableRow);
+        pagination.total = res.data?.total ?? 0;
+      } else {
+        dataList.value = [];
+        pagination.total = 0;
+        ElMessage.error(res.msg || "鏌ヨ澶辫触");
+      }
+    })
+    .catch(() => {
+      dataList.value = [];
+      pagination.total = 0;
+      ElMessage.error("鏌ヨ澶辫触");
+    })
+    .finally(() => {
+      tableLoading.value = false;
+    });
 };
 
-const resetFilters = () => {
-  filters.applyCode = "";
-  filters.supplierId = "";
-  filters.status = "";
+const onSearch = () => {
   pagination.currentPage = 1;
   getTableData();
 };
 
-const changePage = ({ current, size }) => {
-  pagination.currentPage = current;
-  pagination.pageSize = size;
+const resetFilters = () => {
+  filters.invoiceApplicationNo = "";
+  filters.supplierId = "";
+  filters.status = "";
+  filters.dateRange = [];
+  pagination.currentPage = 1;
   getTableData();
 };
 
-const handleSelectionChange = (selection) => {
-  selectedRows.value = selection;
+const changePage = ({ page, limit }) => {
+  pagination.currentPage = page;
+  pagination.pageSize = limit;
+  getTableData();
+};
+
+const closeDialog = () => {
+  dialogVisible.value = false;
+  isView.value = false;
+  isEdit.value = false;
+  inboundSelectVisible.value = false;
+};
+
+const resetForm = () => {
+  Object.assign(form, {
+    invoiceApplicationNo: "",
+    supplierId: "",
+    paymentAmount: 0,
+    paymentMethod: getDefaultPaymentMethod(),
+    applyDate: new Date().toISOString().split("T")[0],
+    paymentContent: "",
+    remark: "",
+    stockInRecordIds: [],
+    inboundBatches: "",
+    status: 0,
+  });
+  inboundBatchList.value = [];
+  inboundBatchOptions.value = [];
 };
 
 const add = () => {
   isEdit.value = false;
+  isView.value = false;
   dialogTitle.value = "鏂板浠樻鐢宠";
-  Object.assign(form, {
-    applyCode: "FK" + Date.now().toString().slice(-8),
-    supplierId: "",
-    amount: 0,
-    paymentMethod: "bank_transfer",
-    applyDate: new Date().toISOString().split('T')[0],
-    expectedDate: "",
-    relatedDocs: [],
-    reason: "",
-    remark: "",
-  });
+  resetForm();
   dialogVisible.value = true;
 };
 
 const edit = (row) => {
   isEdit.value = true;
+  isView.value = false;
   currentId.value = row.id;
   dialogTitle.value = "缂栬緫浠樻鐢宠";
-  Object.assign(form, row);
+  fillFormFromRow(row);
   dialogVisible.value = true;
 };
 
 const view = (row) => {
-  ElMessage.info(`鏌ョ湅鐢宠鍗�: ${row.applyCode}`);
+  isView.value = true;
+  isEdit.value = false;
+  dialogTitle.value = "鏌ョ湅浠樻鐢宠";
+  fillFormFromRow(row);
+  if (row.supplierId) {
+    loadInboundBatches(row.supplierId, true, false);
+  }
+  dialogVisible.value = true;
+};
+
+const submitAudit = (row, status) => {
+  auditAccountPaymentApplication(buildPayloadFromRow(row, status))
+    .then((res) => {
+      if (res.code === 200) {
+        ElMessage.success(status === 1 ? "瀹℃牳閫氳繃" : "瀹℃牳涓嶉�氳繃");
+        getTableData();
+      } else {
+        ElMessage.error(res.msg || "瀹℃牳澶辫触");
+      }
+    })
+    .catch(() => {
+      ElMessage.error("瀹℃牳澶辫触");
+    });
 };
 
 const handleAudit = (row) => {
-  ElMessageBox.confirm("纭瀹℃壒閫氳繃璇ヤ粯娆剧敵璇峰悧锛�", "鎻愮ず", {
-    confirmButtonText: "閫氳繃",
-    cancelButtonText: "椹冲洖",
+  ElMessageBox.confirm("璇烽�夋嫨瀹℃牳缁撴灉", "浠樻鐢宠瀹℃牳", {
+    confirmButtonText: "瀹℃牳閫氳繃",
+    cancelButtonText: "瀹℃牳涓嶉�氳繃",
     distinguishCancelAndClose: true,
     type: "warning",
-  }).then(() => {
-    const index = mockData.findIndex(item => item.id === row.id);
-    if (index !== -1) {
-      mockData[index].status = "approved";
-    }
-    ElMessage.success("瀹℃壒閫氳繃");
-    getTableData();
-  }).catch((action) => {
-    if (action === "cancel") {
-      const index = mockData.findIndex(item => item.id === row.id);
-      if (index !== -1) {
-        mockData[index].status = "rejected";
+  })
+    .then(() => {
+      submitAudit(row, 1);
+    })
+    .catch((action) => {
+      if (action === "cancel") {
+        submitAudit(row, 2);
       }
-      ElMessage.warning("宸查┏鍥�");
-      getTableData();
-    }
+    });
+};
+
+const openPaymentDialog = (row) => {
+  Object.assign(paymentForm, {
+    paymentNumber: "",
+    invoiceApplicationNo: row.invoiceApplicationNo ?? row.applyCode ?? "",
+    supplierName: row.supplierName ?? "",
+    supplierId: row.supplierId,
+    accountPaymentApplicationId: row.id,
+    paymentDate: new Date().toISOString().split("T")[0],
+    paymentAmount: Number(row.paymentAmount ?? row.amount ?? 0),
+    paymentMethod: row.paymentMethod ?? getDefaultPaymentMethod(),
+    bankAccount: row.bankAccountNum ?? row.bankAccount ?? "",
+    bankName: row.bankAccountName ?? row.bankName ?? "",
+    remark: "",
+  });
+  paymentDialogVisible.value = true;
+  nextTick(() => {
+    paymentFormRef.value?.clearValidate();
   });
 };
 
-const handleBatchApply = () => {
-  ElMessage.success(`鎵归噺鐢宠 ${selectedRows.value.length} 鏉¤褰昤);
+const submitPayment = () => {
+  paymentFormRef.value?.validate((valid) => {
+    if (!valid) return;
+    paymentSubmitLoading.value = true;
+    addAccountPurchasePayment({
+      accountPaymentApplicationId: paymentForm.accountPaymentApplicationId,
+      supplierId: paymentForm.supplierId,
+      paymentDate: paymentForm.paymentDate,
+      paymentMethod: paymentForm.paymentMethod,
+      paymentAmount: paymentForm.paymentAmount,
+      paymentNumber: paymentForm.paymentNumber || "",
+      remark: paymentForm.remark || "",
+    })
+      .then((res) => {
+        if (res.code === 200) {
+          ElMessage.success("浠樻鎴愬姛");
+          paymentDialogVisible.value = false;
+          getTableData();
+        } else {
+          ElMessage.error(res.msg || "浠樻澶辫触");
+        }
+      })
+      .catch(() => {
+        ElMessage.error("浠樻澶辫触");
+      })
+      .finally(() => {
+        paymentSubmitLoading.value = false;
+      });
+  });
+};
+
+const handleDelete = (row) => {
+  ElMessageBox.confirm(`纭鍒犻櫎鐢宠鍗曘��${row.applyCode ?? row.invoiceApplicationNo}銆嶅悧锛焋, "鎻愮ず", {
+    confirmButtonText: "纭畾",
+    cancelButtonText: "鍙栨秷",
+    type: "warning",
+  }).then(() => {
+    deleteAccountPaymentApplication([row.id])
+      .then((res) => {
+        if (res.code === 200) {
+          ElMessage.success("鍒犻櫎鎴愬姛");
+          getTableData();
+        } else {
+          ElMessage.error(res.msg || "鍒犻櫎澶辫触");
+        }
+      })
+      .catch(() => {
+        ElMessage.error("鍒犻櫎澶辫触");
+      });
+  });
 };
 
 const submitForm = () => {
-  formRef.value.validate((valid) => {
-    if (valid) {
-      const supplier = supplierList.find(item => item.id === form.supplierId);
-      if (isEdit.value) {
-        const index = mockData.findIndex(item => item.id === currentId.value);
-        if (index !== -1) {
-          mockData[index] = { ...mockData[index], ...form, supplierName: supplier?.name };
+  formRef.value?.validate((valid) => {
+    if (!valid) return;
+    submitLoading.value = true;
+    const request = isEdit.value
+      ? updateAccountPaymentApplication(buildSubmitPayload(true))
+      : addAccountPaymentApplication(buildSubmitPayload(false));
+
+    request
+      .then((res) => {
+        if (res.code === 200) {
+          ElMessage.success(isEdit.value ? "缂栬緫鎴愬姛" : "鏂板鎴愬姛");
+          closeDialog();
+          pagination.currentPage = 1;
+          getTableData();
+        } else {
+          ElMessage.error(res.msg || "淇濆瓨澶辫触");
         }
-        ElMessage.success("缂栬緫鎴愬姛");
-      } else {
-        const newId = mockData.length > 0 ? Math.max(...mockData.map(item => item.id)) + 1 : 1;
-        mockData.push({ id: newId, ...form, supplierName: supplier?.name, status: "pending" });
-        ElMessage.success("鏂板鎴愬姛");
-      }
-      dialogVisible.value = false;
-      getTableData();
-    }
+      })
+      .catch(() => {
+        ElMessage.error("淇濆瓨澶辫触");
+      })
+      .finally(() => {
+        submitLoading.value = false;
+      });
   });
 };
 
+const ensureInboundOptionsForSelected = () => {
+  const ids = form.stockInRecordIds || [];
+  ids.forEach((id) => {
+    const exists = inboundBatchOptions.value.some((opt) => isSameInboundId(opt.value, id));
+    if (exists) return;
+    const fromList = inboundBatchList.value.find((row) => isSameInboundId(getInboundRowId(row), id));
+    if (fromList) {
+      const [option] = normalizeInboundBatchOptions([fromList]);
+      if (option) inboundBatchOptions.value.push(option);
+      return;
+    }
+    inboundBatchOptions.value.push({
+      label: String(id),
+      value: id,
+      inboundAmount: 0,
+    });
+  });
+};
+
+const restoreInboundTableSelection = () => {
+  nextTick(() => {
+    const table = inboundTableRef.value;
+    if (!table) return;
+    table.clearSelection();
+    const selectedIds = new Set((form.stockInRecordIds || []).map((id) => String(id)));
+    inboundBatchList.value.forEach((row) => {
+      const rowId = getInboundRowId(row);
+      if (rowId !== undefined && rowId !== null && selectedIds.has(String(rowId))) {
+        table.toggleRowSelection(row, true);
+      }
+    });
+  });
+};
+
+const loadInboundBatches = (supplierId, keepSelected = false, syncAmount = true) => {
+  if (!supplierId) {
+    inboundBatchList.value = [];
+    inboundBatchOptions.value = [];
+    if (!keepSelected) {
+      form.stockInRecordIds = [];
+      form.inboundBatches = "";
+      form.paymentAmount = 0;
+    }
+    return Promise.resolve();
+  }
+  inboundBatchLoading.value = true;
+  return getInboundBatchesBySupplier({ supplierId })
+    .then((res) => {
+      if (res.code === 200) {
+        const list = res.data?.records ?? res.data ?? [];
+        inboundBatchList.value = Array.isArray(list) ? list : [];
+        inboundBatchOptions.value = normalizeInboundBatchOptions(list);
+      } else {
+        inboundBatchList.value = [];
+        inboundBatchOptions.value = [];
+      }
+    })
+    .catch(() => {
+      inboundBatchList.value = [];
+      inboundBatchOptions.value = [];
+    })
+    .finally(() => {
+      inboundBatchLoading.value = false;
+      if (keepSelected) {
+        ensureInboundOptionsForSelected();
+        restoreInboundTableSelection();
+        if (syncAmount && !isView.value) {
+          syncPaymentAmount();
+        }
+      }
+    });
+};
+
+const handleSupplierChange = (supplierId) => {
+  form.stockInRecordIds = [];
+  form.inboundBatches = "";
+  form.paymentAmount = 0;
+  loadInboundBatches(supplierId);
+};
+
+const handleInboundInputClick = () => {
+  if (isEdit.value || isView.value) return;
+  openInboundSelectDialog();
+};
+
+const openInboundSelectDialog = () => {
+  if (!form.supplierId || isEdit.value || isView.value) return;
+  inboundSelectVisible.value = true;
+  loadInboundBatches(form.supplierId, true, false).then(() => {
+    restoreInboundTableSelection();
+  });
+};
+
+const handleInboundDialogSelectionChange = (selection) => {
+  dialogInboundSelection.value = selection;
+};
+
+const confirmInboundSelection = () => {
+  if (dialogInboundSelection.value.length === 0) {
+    ElMessage.warning("璇疯嚦灏戦�夋嫨涓�鏉″叆搴撳崟");
+    return;
+  }
+  form.stockInRecordIds = dialogInboundSelection.value
+    .map((row) => getInboundRowId(row))
+    .filter((id) => id !== undefined && id !== null);
+  form.inboundBatches = dialogInboundSelection.value
+    .map((row) => row.inboundBatches ?? row.batchNo ?? "")
+    .filter(Boolean)
+    .join("銆�");
+  dialogInboundSelection.value.forEach((row) => {
+    const [option] = normalizeInboundBatchOptions([row]);
+    if (option && !inboundBatchOptions.value.some((opt) => isSameInboundId(opt.value, option.value))) {
+      inboundBatchOptions.value.push(option);
+    }
+  });
+  inboundSelectVisible.value = false;
+  syncPaymentAmount();
+  formRef.value?.validateField("stockInRecordIds");
+};
+
+const handleInboundDialogClosed = () => {
+  dialogInboundSelection.value = [];
+};
+
 onMounted(() => {
+  getSupplierList();
   getTableData();
 });
 </script>
@@ -357,4 +1009,8 @@
   color: #f56c6c;
   font-weight: bold;
 }
+
+.inbound-batch-input :deep(.el-input__wrapper) {
+  cursor: pointer;
+}
 </style>
diff --git a/src/views/financialManagement/payable/purchaseIn.vue b/src/views/financialManagement/payable/purchaseIn.vue
index 4fadcbb..ebc8f0c 100644
--- a/src/views/financialManagement/payable/purchaseIn.vue
+++ b/src/views/financialManagement/payable/purchaseIn.vue
@@ -6,7 +6,14 @@
         <el-input v-model="filters.inboundBatches" placeholder="璇疯緭鍏ュ叆搴撳崟鍙�" clearable style="width: 200px;" />
       </el-form-item>
       <el-form-item label="渚涘簲鍟�:">
-        <el-input v-model="filters.supplierName" placeholder="璇疯緭鍏ヤ緵搴斿晢" clearable style="width: 200px;" />
+        <el-select v-model="filters.supplierId" placeholder="璇烽�夋嫨渚涘簲鍟�" clearable filterable style="width: 200px;">
+          <el-option
+            v-for="item in supplierList"
+            :key="item.id"
+            :label="item.supplierName"
+            :value="item.id"
+          />
+        </el-select>
       </el-form-item>
       <el-form-item label="鍏ュ簱鏃ユ湡:">
         <el-date-picker
@@ -45,7 +52,7 @@
         @pagination="changePage"
       >
         <template #inboundDate="{ row }">
-          {{ row.InboundDate || row.inboundDate || "" }}
+          {{ row.inboundDate ?? row.InboundDate ?? "" }}
         </template>
       </PIMTable>
     </div>
@@ -56,6 +63,7 @@
 import { ref, reactive, onMounted, getCurrentInstance } from "vue";
 import { ElMessage } from "element-plus";
 import { listPageAccountPurchase } from "@/api/financialManagement/accountPurchase";
+import { listSupplier } from "@/api/basicData/supplierManageFile.js";
 
 defineOptions({
   name: "閲囪喘鍏ュ簱",
@@ -65,7 +73,7 @@
 
 const filters = reactive({
   inboundBatches: "",
-  supplierName: "",
+  supplierId: "",
   dateRange: [],
 });
 
@@ -80,7 +88,7 @@
   { label: "渚涘簲鍟�", prop: "supplierName", minWidth: "180" },
   {
     label: "鍏ュ簱鏃ユ湡",
-    prop: "InboundDate",
+    prop: "inboundDate",
     minWidth: "170",
     dataType: "slot",
     slot: "inboundDate",
@@ -92,18 +100,30 @@
 
 const dataList = ref([]);
 const tableLoading = ref(false);
+const supplierList = ref([]);
 
-function buildFilterParams() {
-  const params = {
-    inboundBatches: filters.inboundBatches || undefined,
-    supplierName: filters.supplierName || undefined,
-  };
-  if (filters.dateRange && filters.dateRange.length === 2) {
+const buildFilterParams = () => {
+  const params = {};
+  if (filters.inboundBatches) {
+    params.inboundBatches = filters.inboundBatches;
+  }
+  if (filters.supplierId) {
+    params.supplierId = filters.supplierId;
+  }
+  if (filters.dateRange?.length === 2) {
     params.startDate = filters.dateRange[0];
     params.endDate = filters.dateRange[1];
   }
   return params;
-}
+};
+
+const getSupplierList = () => {
+  listSupplier({ current: -1, size: -1, isWhite: 0 }).then((res) => {
+    if (res.code === 200) {
+      supplierList.value = res.data?.records ?? [];
+    }
+  });
+};
 
 const onSearch = () => {
   pagination.currentPage = 1;
@@ -125,10 +145,13 @@
       } else {
         ElMessage.error(res.msg || "鏌ヨ澶辫触");
         dataList.value = [];
+        pagination.total = 0;
       }
     })
     .catch(() => {
       dataList.value = [];
+      pagination.total = 0;
+      ElMessage.error("鏌ヨ澶辫触");
     })
     .finally(() => {
       tableLoading.value = false;
@@ -137,7 +160,7 @@
 
 const resetFilters = () => {
   filters.inboundBatches = "";
-  filters.supplierName = "";
+  filters.supplierId = "";
   filters.dateRange = [];
   pagination.currentPage = 1;
   getTableData();
@@ -153,11 +176,12 @@
   proxy.download(
     "/accountPurchase/exportAccountPurchaseInbound",
     buildFilterParams(),
-    `閲囪喘鍏ュ簱_${new Date().getTime()}.xlsx`
+    `閲囪喘鍏ュ簱_${Date.now()}.xlsx`
   );
 };
 
 onMounted(() => {
+  getSupplierList();
   getTableData();
 });
 </script>
diff --git a/src/views/financialManagement/payable/purchaseReturn.vue b/src/views/financialManagement/payable/purchaseReturn.vue
index e7ca665..eeec383 100644
--- a/src/views/financialManagement/payable/purchaseReturn.vue
+++ b/src/views/financialManagement/payable/purchaseReturn.vue
@@ -1,26 +1,20 @@
 <template>
   <!-- 閲囪喘閫�璐� -->
-
   <div class="app-container">
     <el-form :model="filters" :inline="true">
       <el-form-item label="閫�璐у崟鍙�:">
-        <el-input
-          v-model="filters.returnNo"
-          placeholder="璇疯緭鍏ラ��璐у崟鍙�"
-          clearable
-          style="width: 200px"
-        />
+        <el-input v-model="filters.returnNo" placeholder="璇疯緭鍏ラ��璐у崟鍙�" clearable style="width: 200px;" />
       </el-form-item>
-
       <el-form-item label="渚涘簲鍟�:">
-        <el-input
-          v-model="filters.supplierName"
-          placeholder="璇疯緭鍏ヤ緵搴斿晢"
-          clearable
-          style="width: 200px"
-        />
+        <el-select v-model="filters.supplierId" placeholder="璇烽�夋嫨渚涘簲鍟�" clearable filterable style="width: 200px;">
+          <el-option
+            v-for="item in supplierList"
+            :key="item.id"
+            :label="item.supplierName"
+            :value="item.id"
+          />
+        </el-select>
       </el-form-item>
-
       <el-form-item label="閫�璐ф棩鏈�:">
         <el-date-picker
           v-model="filters.dateRange"
@@ -33,23 +27,18 @@
           clearable
         />
       </el-form-item>
-
       <el-form-item>
         <el-button type="primary" @click="onSearch">鎼滅储</el-button>
-
         <el-button @click="resetFilters">閲嶇疆</el-button>
       </el-form-item>
     </el-form>
-
     <div class="table_list">
       <div class="actions">
         <div></div>
-
         <div>
           <el-button @click="handleOut" icon="Download">瀵煎嚭</el-button>
         </div>
       </div>
-
       <PIMTable
         rowKey="id"
         :column="columns"
@@ -57,9 +46,7 @@
         :tableLoading="tableLoading"
         :page="{
           current: pagination.currentPage,
-
           size: pagination.pageSize,
-
           total: pagination.total,
         }"
         @pagination="changePage"
@@ -68,14 +55,11 @@
   </div>
 </template>
 
-
-
 <script setup>
 import { ref, reactive, onMounted, getCurrentInstance } from "vue";
-
 import { ElMessage } from "element-plus";
-
 import { listPageAccountPurchaseReturn } from "@/api/financialManagement/accountPurchase";
+import { listSupplier } from "@/api/basicData/supplierManageFile.js";
 
 defineOptions({
   name: "閲囪喘閫�璐�",
@@ -85,38 +69,26 @@
 
 const filters = reactive({
   returnNo: "",
-
-  supplierName: "",
-
+  supplierId: "",
   dateRange: [],
 });
 
 const pagination = reactive({
   currentPage: 1,
-
   pageSize: 10,
-
   total: 0,
 });
 
 const columns = [
   { label: "閫�璐у崟鍙�", prop: "returnNo", minWidth: "150" },
-
   { label: "渚涘簲鍟�", prop: "supplierName", minWidth: "180" },
-
   { label: "鍏宠仈鍏ュ簱鍗曞彿", prop: "inboundBatches", minWidth: "150" },
-
   { label: "閫�璐ф棩鏈�", prop: "preparedAt", minWidth: "170" },
-
   {
     label: "閫�娆炬�婚",
-
     prop: "totalAmount",
-
     minWidth: "150",
-
     align: "right",
-
     formatData: (val) =>
       val === null || val === undefined || val === ""
         ? ""
@@ -125,66 +97,65 @@
             maximumFractionDigits: 2,
           }),
   },
-
   { label: "閫�璐ф柟寮�", prop: "returnType", minWidth: "150" },
-
   { label: "閲囪喘璁㈠崟鍙�", prop: "purchaseContractNumber", minWidth: "150" },
 ];
 
 const dataList = ref([]);
-
 const tableLoading = ref(false);
+const supplierList = ref([]);
 
-function buildFilterParams() {
-  const params = {
-    returnNo: filters.returnNo || undefined,
-
-    supplierName: filters.supplierName || undefined,
-  };
-
-  if (filters.dateRange && filters.dateRange.length === 2) {
+const buildFilterParams = () => {
+  const params = {};
+  if (filters.returnNo) {
+    params.returnNo = filters.returnNo;
+  }
+  if (filters.supplierId) {
+    params.supplierId = filters.supplierId;
+  }
+  if (filters.dateRange?.length === 2) {
     params.startDate = filters.dateRange[0];
-
     params.endDate = filters.dateRange[1];
   }
-
   return params;
-}
+};
+
+const getSupplierList = () => {
+  listSupplier({ current: -1, size: -1, isWhite: 0 }).then((res) => {
+    if (res.code === 200) {
+      supplierList.value = res.data?.records ?? [];
+    }
+  });
+};
 
 const onSearch = () => {
   pagination.currentPage = 1;
-
   getTableData();
 };
 
 const getTableData = () => {
   tableLoading.value = true;
-
   listPageAccountPurchaseReturn({
     ...buildFilterParams(),
-
     current: pagination.currentPage,
-
     size: pagination.pageSize,
   })
     .then((res) => {
       const ok = res.code === 200 || res.code === 0;
-
       if (ok && res.data) {
         pagination.total = res.data.total ?? 0;
-
         dataList.value = res.data.records ?? [];
       } else {
         ElMessage.error(res.msg || "鏌ヨ澶辫触");
-
         dataList.value = [];
+        pagination.total = 0;
       }
     })
-
     .catch(() => {
       dataList.value = [];
+      pagination.total = 0;
+      ElMessage.error("鏌ヨ澶辫触");
     })
-
     .finally(() => {
       tableLoading.value = false;
     });
@@ -192,48 +163,36 @@
 
 const resetFilters = () => {
   filters.returnNo = "";
-
-  filters.supplierName = "";
-
+  filters.supplierId = "";
   filters.dateRange = [];
-
   pagination.currentPage = 1;
-
   getTableData();
 };
 
 const changePage = ({ page, limit }) => {
   pagination.currentPage = page;
-
   pagination.pageSize = limit;
-
   getTableData();
 };
 
 const handleOut = () => {
   proxy.download(
     "/accountPurchase/exportAccountPurchaseReturn",
-
     buildFilterParams(),
-
-    `閲囪喘閫�璐${new Date().getTime()}.xlsx`
+    `閲囪喘閫�璐${Date.now()}.xlsx`
   );
 };
 
 onMounted(() => {
+  getSupplierList();
   getTableData();
 });
 </script>
 
-
-
 <style lang="scss" scoped>
 .actions {
   display: flex;
-
   justify-content: space-between;
-
   margin-bottom: 15px;
 }
 </style>
-
diff --git a/src/views/financialManagement/payable/reconciliation.vue b/src/views/financialManagement/payable/reconciliation.vue
index 3aa23cd..e749e56 100644
--- a/src/views/financialManagement/payable/reconciliation.vue
+++ b/src/views/financialManagement/payable/reconciliation.vue
@@ -2,8 +2,13 @@
   <div class="app-container">
     <el-form :model="filters" :inline="true">
       <el-form-item label="渚涘簲鍟�:">
-        <el-select v-model="filters.supplierId" placeholder="璇烽�夋嫨渚涘簲鍟�" clearable style="width: 200px;">
-          <el-option v-for="item in supplierList" :key="item.id" :label="item.name" :value="item.id" />
+        <el-select v-model="filters.supplierId" placeholder="璇烽�夋嫨渚涘簲鍟�" clearable filterable style="width: 200px;">
+          <el-option
+            v-for="item in supplierList"
+            :key="item.id"
+            :label="item.supplierName"
+            :value="item.id"
+          />
         </el-select>
       </el-form-item>
       <el-form-item label="瀵硅处鏈熼棿:">
@@ -12,7 +17,7 @@
         <el-date-picker v-model="filters.endMonth" type="month" placeholder="缁撴潫鏈堜唤" value-format="YYYY-MM" style="width: 140px;" />
       </el-form-item>
       <el-form-item>
-        <el-button type="primary" @click="getTableData">鎼滅储</el-button>
+        <el-button type="primary" @click="onSearch">鎼滅储</el-button>
         <el-button @click="resetFilters">閲嶇疆</el-button>
       </el-form-item>
     </el-form>
@@ -29,6 +34,7 @@
         rowKey="id"
         :column="columns"
         :tableData="dataList"
+        :tableLoading="tableLoading"
         :page="{
           current: pagination.currentPage,
           size: pagination.pageSize,
@@ -36,21 +42,21 @@
         }"
         @pagination="changePage"
       >
-        <template #beginBalance="{ row }">
-          <span :class="row.beginBalance >= 0 ? 'text-success' : 'text-danger'">楼{{ formatMoney(row.beginBalance) }}</span>
+        <template #openingBalance="{ row }">
+          <span :class="row.openingBalance >= 0 ? 'text-success' : 'text-danger'">楼{{ formatMoney(row.openingBalance) }}</span>
         </template>
-        <template #currentPayable="{ row }">
-          <span class="text-danger">楼{{ formatMoney(row.currentPayable) }}</span>
+        <template #currentPlan="{ row }">
+          <span class="text-danger">楼{{ formatMoney(row.currentPlan) }}</span>
         </template>
-        <template #currentPayment="{ row }">
-          <span class="text-success">楼{{ formatMoney(row.currentPayment) }}</span>
+        <template #currentActually="{ row }">
+          <span class="text-success">楼{{ formatMoney(row.currentActually) }}</span>
         </template>
-        <template #endBalance="{ row }">
-          <span :class="row.endBalance >= 0 ? 'text-success' : 'text-danger'">楼{{ formatMoney(row.endBalance) }}</span>
+        <template #closingBalance="{ row }">
+          <span :class="row.closingBalance >= 0 ? 'text-success' : 'text-danger'">楼{{ formatMoney(row.closingBalance) }}</span>
         </template>
         <template #operation="{ row }">
           <el-button type="primary" link @click="viewDetail(row)">鏌ョ湅鏄庣粏</el-button>
-          <el-button type="primary" link @click="printStatement(row)">鎵撳嵃</el-button>
+          <el-button type="danger" link @click="handleDelete(row)">鍒犻櫎</el-button>
         </template>
       </PIMTable>
     </div>
@@ -60,7 +66,7 @@
         <h3>{{ currentSupplier }} 搴斾粯瀵硅处鍗�</h3>
         <p>瀵硅处鏈熼棿: {{ currentPeriod }}</p>
       </div>
-      <el-table :data="detailData" border style="width: 100%">
+      <el-table :data="detailData" border style="width: 100%" v-loading="detailLoading">
         <el-table-column prop="date" label="鏃ユ湡" width="120" />
         <el-table-column prop="type" label="绫诲瀷" width="100">
           <template #default="{ row }">
@@ -77,6 +83,7 @@
         <el-table-column prop="credit" label="璐锋柟(搴斾粯)" width="120">
           <template #default="{ row }">
             <span v-if="row.credit > 0" class="text-danger">楼{{ formatMoney(row.credit) }}</span>
+            <span v-else-if="row.credit < 0" class="text-success">楼{{ formatMoney(Math.abs(row.credit)) }}</span>
             <span v-else>-</span>
           </template>
         </el-table-column>
@@ -98,52 +105,80 @@
         <el-row :gutter="20">
           <el-col :span="12">
             <el-form-item label="閫夋嫨渚涘簲鍟�" prop="supplierId">
-              <el-select v-model="generateForm.supplierId" placeholder="璇烽�夋嫨渚涘簲鍟�" style="width: 100%;" @change="onSupplierChange">
-                <el-option v-for="item in supplierList" :key="item.id" :label="item.name" :value="item.id" />
+              <el-select
+                v-model="generateForm.supplierId"
+                placeholder="璇烽�夋嫨渚涘簲鍟�"
+                style="width: 100%;"
+                filterable
+                @change="onSupplierChange"
+              >
+                <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="period">
-              <el-date-picker v-model="generateForm.period" type="month" placeholder="閫夋嫨鏈堜唤" value-format="YYYY-MM" style="width: 100%;" @change="onPeriodChange" />
+            <el-form-item label="瀵硅处鏈堜唤" prop="statementMonth">
+              <el-date-picker
+                v-model="generateForm.statementMonth"
+                type="month"
+                placeholder="閫夋嫨鏈堜唤"
+                value-format="YYYY-MM"
+                style="width: 100%;"
+                @change="onStatementMonthChange"
+              />
             </el-form-item>
           </el-col>
         </el-row>
       </el-form>
 
-      <div v-if="purchaseData.length > 0" class="purchase-section">
-        <div class="section-title">鏈湀閲囪喘鏁版嵁</div>
-        <el-table :data="purchaseData" border style="width: 100%; margin-bottom: 15px;" v-loading="purchaseLoading" @selection-change="handlePurchaseSelectionChange">
+      <div v-if="statementDetailLoaded" class="purchase-section">
+        <div v-if="purchaseData.length > 0" class="section-title">鏈湀閲囪喘鏁版嵁</div>
+        <el-table
+          v-if="purchaseData.length > 0"
+          ref="purchaseTableRef"
+          :data="purchaseData"
+          border
+          row-key="id"
+          style="width: 100%; margin-bottom: 15px;"
+          v-loading="purchaseLoading"
+          @selection-change="handlePurchaseSelectionChange"
+        >
           <el-table-column type="selection" width="55" align="center" />
-          <el-table-column prop="date" label="鏃ユ湡" width="120" />
-          <el-table-column prop="code" label="鍗曟嵁缂栧彿" width="150" />
+          <el-table-column prop="occurrenceDate" label="鏃ユ湡" width="120" />
+          <el-table-column prop="receiptNumber" label="鍗曟嵁缂栧彿" width="150" />
           <el-table-column prop="type" label="绫诲瀷" width="100">
             <template #default="{ row }">
-              <el-tag :type="row.type === '鍏ュ簱' ? 'success' : 'danger'">{{ row.type }}</el-tag>
+              <el-tag :type="getDetailTypeTagType(row.type)">{{ row.typeLabel }}</el-tag>
             </template>
           </el-table-column>
           <el-table-column prop="amount" label="閲戦" width="120">
             <template #default="{ row }">
-              <span :class="row.type === '鍏ュ簱' ? 'text-danger' : 'text-success'">楼{{ formatMoney(row.amount) }}</span>
+              <span :class="getDetailAmountClass(row.type)">楼{{ formatMoney(row.amount) }}</span>
             </template>
           </el-table-column>
           <el-table-column prop="remark" label="澶囨敞" />
         </el-table>
+        <el-empty v-else description="璇ヤ緵搴斿晢鏈湀鏆傛棤鏄庣粏鏁版嵁" :image-size="80" />
 
         <div class="summary-row">
-          <span>鏈熷垵浣欓: <strong class="text-primary">楼{{ formatMoney(generateForm.beginBalance) }}</strong></span>
-          <span>鏈湡搴斾粯: <strong class="text-danger">楼{{ formatMoney(generateForm.currentPayable) }}</strong></span>
-          <span>鏈湡浠樻: <strong class="text-success">楼{{ formatMoney(generateForm.currentPayment) }}</strong></span>
-          <span>鏈熸湯浣欓: <strong class="text-primary">楼{{ formatMoney(calculateEndBalance(generateForm.beginBalance, generateForm.currentPayable, generateForm.currentPayment)) }}</strong></span>
+          <span>鏈熷垵浣欓: <strong class="text-primary">楼{{ formatMoney(generateForm.openingBalance) }}</strong></span>
+          <span>鏈湡搴斾粯: <strong class="text-danger">楼{{ formatMoney(generateForm.currentPlan) }}</strong></span>
+          <span>鏈湡浠樻: <strong class="text-success">楼{{ formatMoney(generateForm.currentActually) }}</strong></span>
+          <span>鏈熸湯浣欓: <strong :class="displayClosingBalance >= 0 ? 'text-success' : 'text-danger'">楼{{ formatMoney(displayClosingBalance) }}</strong></span>
         </div>
       </div>
 
-      <div v-else-if="generateForm.supplierId && !purchaseLoading" class="empty-tip">
+      <div v-else-if="generateForm.supplierId && generateForm.statementMonth && !purchaseLoading" class="empty-tip">
         <el-empty description="璇ヤ緵搴斿晢鏈湀鏆傛棤閲囪喘鏁版嵁" />
       </div>
 
       <template #footer>
-        <el-button type="primary" @click="confirmGenerate" :disabled="!canGenerate">纭鐢熸垚</el-button>
+        <el-button type="primary" @click="confirmGenerate" :disabled="!canGenerate" :loading="submitLoading">纭鐢熸垚</el-button>
         <el-button @click="generateDialogVisible = false">鍙栨秷</el-button>
       </template>
     </FormDialog>
@@ -151,9 +186,20 @@
 </template>
 
 <script setup>
-import { ref, reactive, onMounted, computed } from "vue";
-import { ElMessage } from "element-plus";
+import { ref, reactive, onMounted, computed, nextTick, getCurrentInstance } from "vue";
+import { ElMessage, ElMessageBox } from "element-plus";
 import FormDialog from "@/components/Dialog/FormDialog.vue";
+import { getOptions } from "@/api/procurementManagement/procurementLedger.js";
+import {
+  getAccountStatementDetailsByMonth,
+  addAccountStatement,
+  listPageAccountStatement,
+  deleteAccountStatement,
+} from "@/api/financialManagement/accountStatement.js";
+
+const ACCOUNT_TYPE_PAYABLE = 2;
+
+const { proxy } = getCurrentInstance();
 
 defineOptions({
   name: "搴斾粯瀵硅处",
@@ -172,56 +218,192 @@
 });
 
 const columns = [
-  { label: "瀵硅处鍗曞彿", prop: "statementCode", width: "150" },
+  { label: "瀵硅处鍗曞彿", prop: "statementNumber", width: "150" },
   { label: "渚涘簲鍟�", prop: "supplierName", width: "180" },
-  { label: "瀵硅处鏈熼棿", prop: "period", width: "150" },
-  { label: "鏈熷垵浣欓", prop: "beginBalance", slot: "beginBalance" },
-  { label: "鏈湡搴斾粯", prop: "currentPayable", slot: "currentPayable" },
-  { label: "鏈湡浠樻", prop: "currentPayment", slot: "currentPayment" },
-  { label: "鏈熸湯浣欓", prop: "endBalance", slot: "endBalance" },
-  { label: "鎿嶄綔", prop: "operation", slot: "operation", width: "150", fixed: "right" },
+  { label: "瀵硅处鏈熼棿", prop: "statementMonth", width: "150" },
+  { label: "鏈熷垵浣欓", prop: "openingBalance", dataType: "slot", slot: "openingBalance" },
+  { label: "鏈湡搴斾粯", prop: "currentPlan", dataType: "slot", slot: "currentPlan" },
+  { label: "鏈湡浠樻", prop: "currentActually", dataType: "slot", slot: "currentActually" },
+  { label: "鏈熸湯浣欓", prop: "closingBalance", dataType: "slot", slot: "closingBalance" },
+  { label: "鎿嶄綔", prop: "operation", dataType: "slot", slot: "operation", width: "200", fixed: "right" },
 ];
 
 const dataList = ref([]);
+const tableLoading = ref(false);
+const submitLoading = ref(false);
 const detailDialogVisible = ref(false);
 const currentSupplier = ref("");
 const currentPeriod = ref("");
 const detailData = ref([]);
+const detailLoading = ref(false);
 
 const generateDialogVisible = ref(false);
 const purchaseLoading = ref(false);
+const statementDetailLoaded = ref(false);
 const purchaseData = ref([]);
 const selectedPurchases = ref([]);
+const purchaseTableRef = ref(null);
+const supplierList = ref([]);
+
+/** 鏄庣粏 type锛�1鍑哄簱 2鍏ュ簱 3鏀舵 4浠樻 5閫�璐� */
+const STATEMENT_DETAIL_TYPE_MAP = {
+  1: "鍑哄簱",
+  2: "鍏ュ簱",
+  3: "鏀舵",
+  4: "浠樻",
+  5: "閫�璐�",
+};
+
+const calculateEndBalance = (openingBalance, currentPlan, currentActually) => {
+  return openingBalance + currentPlan - currentActually;
+};
+
+const getDetailTypeLabel = (type) => STATEMENT_DETAIL_TYPE_MAP[Number(type)] ?? "";
+
+const getDetailTypeTagType = (type) => {
+  const t = Number(type);
+  if (t === 2) return "success";
+  if (t === 4) return "primary";
+  if (t === 5) return "danger";
+  return "info";
+};
+
+const getDetailAmountClass = (type) => {
+  const t = Number(type);
+  if (t === 2) return "text-danger";
+  if (t === 4) return "text-success";
+  return "text-danger";
+};
 
 const generateForm = reactive({
   supplierId: "",
   supplierName: "",
-  period: "",
-  beginBalance: 0,
-  currentPayable: 0,
-  currentPayment: 0,
+  statementMonth: "",
+  openingBalance: 0,
+  currentPlan: 0,
+  currentActually: 0,
+  closingBalance: 0,
 });
 
-const canGenerate = computed(() => {
-  return generateForm.supplierId && generateForm.period && selectedPurchases.value.length > 0;
-});
+const displayClosingBalance = computed(() =>
+  calculateEndBalance(
+    generateForm.openingBalance,
+    generateForm.currentPlan,
+    generateForm.currentActually
+  )
+);
 
-const supplierList = [
-  { id: 1, name: "鍖椾含鍘熸潗鏂欎緵搴斿晢" },
-  { id: 2, name: "涓婃捣鐢靛瓙鍏冨櫒浠跺叕鍙�" },
-  { id: 3, name: "骞垮窞鍖呰鏉愭枡鍘�" },
-  { id: 4, name: "娣卞湷浜旈噾閰嶄欢鍏徃" },
-];
+const canGenerate = computed(
+  () => generateForm.supplierId && generateForm.statementMonth && selectedPurchases.value.length > 0
+);
 
-const mockData = [
-  { id: 1, statementCode: "DZ202401001", supplierId: 1, supplierName: "鍖椾含鍘熸潗鏂欎緵搴斿晢", period: "2024-01", beginBalance: 20000, currentPayable: 15000, currentPayment: 10000, endBalance: 25000 },
-  { id: 2, statementCode: "DZ202401002", supplierId: 2, supplierName: "涓婃捣鐢靛瓙鍏冨櫒浠跺叕鍙�", period: "2024-01", beginBalance: 10000, currentPayable: 20000, currentPayment: 15000, endBalance: 15000 },
-  { id: 3, statementCode: "DZ202402001", supplierId: 1, supplierName: "鍖椾含鍘熸潗鏂欎緵搴斿晢", period: "2024-02", beginBalance: 25000, currentPayable: 18000, currentPayment: 20000, endBalance: 23000 },
-];
-
-const calculateEndBalance = (beginBalance, currentPayable, currentPayment) => {
-  return beginBalance + currentPayable - currentPayment;
+const applyStatementSummary = (data) => {
+  generateForm.openingBalance = Number(data.openingBalance ?? 0);
+  generateForm.currentPlan = Number(data.currentPlan ?? 0);
+  generateForm.currentActually = Number(data.currentActually ?? 0);
+  generateForm.closingBalance = Number(
+    data.closingBalance ??
+      calculateEndBalance(
+        generateForm.openingBalance,
+        generateForm.currentPlan,
+        generateForm.currentActually
+      )
+  );
 };
+
+const getSupplierList = () => {
+  getOptions().then((res) => {
+    if (res.code === 200) {
+      supplierList.value = res.data ?? [];
+    }
+  });
+};
+
+const normalizePurchaseRows = (list) => {
+  const rows = Array.isArray(list) ? list : [];
+  return rows.map((item, index) => {
+    const type = Number(item.type);
+    return {
+      id: item.id ?? `detail-${index}`,
+      accountStatementId: item.accountStatementId,
+      occurrenceDate: item.occurrenceDate ?? "",
+      receiptNumber: item.receiptNumber ?? "",
+      type,
+      typeLabel: getDetailTypeLabel(type),
+      amount: Math.abs(Number(item.amount ?? 0)),
+      remark: item.remark ?? "",
+    };
+  });
+};
+
+const selectAllPurchaseRows = (keepApiSummary = false) => {
+  nextTick(() => {
+    const table = purchaseTableRef.value;
+    if (!table) return;
+    table.clearSelection();
+    purchaseData.value.forEach((row) => table.toggleRowSelection(row, true));
+    selectedPurchases.value = [...purchaseData.value];
+    if (!keepApiSummary) {
+      calculateSummary();
+    }
+  });
+};
+
+const isNumericId = (id) => id !== undefined && id !== null && id !== "" && /^\d+$/.test(String(id));
+
+const buildFilterParams = (params = {}) => {
+  const result = { ...params, accountType: ACCOUNT_TYPE_PAYABLE };
+  if (filters.supplierId) {
+    result.customerId = filters.supplierId;
+  }
+  if (filters.startMonth && filters.endMonth && filters.startMonth === filters.endMonth) {
+    result.statementMonth = filters.startMonth;
+  } else if (filters.startMonth) {
+    result.startMonth = filters.startMonth;
+  }
+  if (filters.endMonth && filters.startMonth !== filters.endMonth) {
+    result.endMonth = filters.endMonth;
+  }
+  return result;
+};
+
+const buildListParams = () =>
+  buildFilterParams({
+    current: pagination.currentPage,
+    size: pagination.pageSize,
+  });
+
+const buildExportParams = () => buildFilterParams({});
+
+const buildDetailSubmitItem = (row) => {
+  const item = {
+    occurrenceDate: row.occurrenceDate,
+    receiptNumber: row.receiptNumber,
+    type: row.type,
+    amount: row.amount,
+    remark: row.remark ?? "",
+  };
+  if (isNumericId(row.id)) {
+    item.id = Number(row.id);
+  }
+  if (row.accountStatementId) {
+    item.accountStatementId = row.accountStatementId;
+  }
+  return item;
+};
+
+const buildAddPayload = () => ({
+  customerId: generateForm.supplierId,
+  customerName: generateForm.supplierName,
+  statementMonth: generateForm.statementMonth,
+  accountType: ACCOUNT_TYPE_PAYABLE,
+  statementNumber: "",
+  openingBalance: generateForm.openingBalance,
+  currentPlan: generateForm.currentPlan,
+  currentActually: generateForm.currentActually,
+  closingBalance: generateForm.closingBalance,
+  accountStatementDetails: selectedPurchases.value.map(buildDetailSubmitItem),
+});
 
 const formatMoney = (value) => {
   if (value === undefined || value === null) return "0.00";
@@ -229,15 +411,35 @@
 };
 
 const getTableData = () => {
-  let result = [...mockData];
-  if (filters.supplierId) {
-    result = result.filter(item => item.supplierId === filters.supplierId);
-  }
-  if (filters.startMonth && filters.endMonth) {
-    result = result.filter(item => item.period >= filters.startMonth && item.period <= filters.endMonth);
-  }
-  pagination.total = result.length;
-  dataList.value = result.slice((pagination.currentPage - 1) * pagination.pageSize, pagination.currentPage * pagination.pageSize);
+  tableLoading.value = true;
+  listPageAccountStatement(buildListParams())
+    .then((res) => {
+      const ok = res.code === 200 || res.code === 0;
+      if (ok && res.data) {
+        pagination.total = res.data.total ?? 0;
+        dataList.value = (res.data.records ?? []).map((row) => ({
+          ...row,
+          supplierName: row.supplierName ?? row.customerName,
+        }));
+      } else {
+        ElMessage.error(res.msg || "鏌ヨ澶辫触");
+        dataList.value = [];
+        pagination.total = 0;
+      }
+    })
+    .catch(() => {
+      dataList.value = [];
+      pagination.total = 0;
+      ElMessage.error("鏌ヨ澶辫触");
+    })
+    .finally(() => {
+      tableLoading.value = false;
+    });
+};
+
+const onSearch = () => {
+  pagination.currentPage = 1;
+  getTableData();
 };
 
 const resetFilters = () => {
@@ -248,92 +450,106 @@
   getTableData();
 };
 
-const changePage = ({ current, size }) => {
-  pagination.currentPage = current;
-  pagination.pageSize = size;
+const changePage = ({ page, limit }) => {
+  pagination.currentPage = page;
+  pagination.pageSize = limit;
   getTableData();
 };
 
 const generateStatement = () => {
   generateForm.supplierId = "";
   generateForm.supplierName = "";
-  generateForm.period = "";
-  generateForm.beginBalance = 0;
-  generateForm.currentPayable = 0;
-  generateForm.currentPayment = 0;
+  generateForm.statementMonth = "";
+  generateForm.openingBalance = 0;
+  generateForm.currentPlan = 0;
+  generateForm.currentActually = 0;
+  generateForm.closingBalance = 0;
+  statementDetailLoaded.value = false;
   purchaseData.value = [];
   selectedPurchases.value = [];
   generateDialogVisible.value = true;
 };
 
 const onSupplierChange = (supplierId) => {
-  const supplier = supplierList.find(item => item.id === supplierId);
-  if (supplier) {
-    generateForm.supplierName = supplier.name;
-  }
+  const supplier = supplierList.value.find((item) => item.id === supplierId);
+  generateForm.supplierName = supplier?.supplierName ?? "";
   loadPurchaseData();
 };
 
-const onPeriodChange = () => {
+const onStatementMonthChange = () => {
   loadPurchaseData();
 };
 
 const loadPurchaseData = () => {
-  if (!generateForm.supplierId || !generateForm.period) {
+  if (!generateForm.supplierId || !generateForm.statementMonth) {
     purchaseData.value = [];
+    selectedPurchases.value = [];
+    statementDetailLoaded.value = false;
+    generateForm.openingBalance = 0;
+    generateForm.currentPlan = 0;
+    generateForm.currentActually = 0;
+    generateForm.closingBalance = 0;
     return;
   }
 
   purchaseLoading.value = true;
+  selectedPurchases.value = [];
+  statementDetailLoaded.value = false;
 
-  setTimeout(() => {
-    const mockPurchaseData = [
-      { id: 1, date: generateForm.period + "-05", code: "RK2024001", type: "鍏ュ簱", amount: 8000, remark: "鍘熸潗鏂欓噰璐�" },
-      { id: 2, date: generateForm.period + "-10", code: "FK2024001", type: "浠樻", amount: 5000, remark: "鏀粯璐ф" },
-      { id: 3, date: generateForm.period + "-15", code: "RK2024002", type: "鍏ュ簱", amount: 12000, remark: "鐢靛瓙鍏冨櫒浠�" },
-      { id: 4, date: generateForm.period + "-18", code: "TH2024001", type: "閫�璐�", amount: 2000, remark: "璐ㄩ噺闂閫�璐�" },
-      { id: 5, date: generateForm.period + "-22", code: "RK2024003", type: "鍏ュ簱", amount: 6000, remark: "鍖呰鏉愭枡" },
-      { id: 6, date: generateForm.period + "-25", code: "FK2024002", type: "浠樻", amount: 8000, remark: "鏀粯璐ф" },
-    ];
+  getAccountStatementDetailsByMonth({
+    accountType: ACCOUNT_TYPE_PAYABLE,
+    customerId: generateForm.supplierId,
+    statementMonth: generateForm.statementMonth,
+  })
+    .then((res) => {
+      if (res.code === 200) {
+        const data = res.data ?? {};
+        const details = data.accountStatementDetails;
+        const list = Array.isArray(details) ? details : [];
+        purchaseData.value = normalizePurchaseRows(list);
+        applyStatementSummary(data);
+        statementDetailLoaded.value = true;
 
-    purchaseData.value = mockPurchaseData;
-
-    const lastPeriod = getLastPeriod(generateForm.period);
-    const lastStatement = mockData.find(item =>
-      item.supplierId === generateForm.supplierId && item.period === lastPeriod
-    );
-    generateForm.beginBalance = lastStatement ? lastStatement.endBalance : 0;
-
-    calculateSummary();
-
-    purchaseLoading.value = false;
-  }, 500);
-};
-
-const getLastPeriod = (period) => {
-  const [year, month] = period.split("-").map(Number);
-  if (month === 1) {
-    return `${year - 1}-12`;
-  }
-  return `${year}-${String(month - 1).padStart(2, "0")}`;
+        if (purchaseData.value.length > 0) {
+          selectAllPurchaseRows(true);
+        }
+      } else {
+        purchaseData.value = [];
+        statementDetailLoaded.value = false;
+        ElMessage.error(res.msg || "鏌ヨ瀵硅处鏄庣粏澶辫触");
+      }
+    })
+    .catch(() => {
+      purchaseData.value = [];
+      statementDetailLoaded.value = false;
+      ElMessage.error("鏌ヨ瀵硅处鏄庣粏澶辫触");
+    })
+    .finally(() => {
+      purchaseLoading.value = false;
+    });
 };
 
 const calculateSummary = () => {
   let payable = 0;
   let payment = 0;
 
-  selectedPurchases.value.forEach(item => {
-    if (item.type === "鍏ュ簱") {
+  selectedPurchases.value.forEach((item) => {
+    if (item.type === 2) {
       payable += item.amount;
-    } else if (item.type === "閫�璐�") {
+    } else if (item.type === 5) {
       payable -= item.amount;
-    } else if (item.type === "浠樻") {
+    } else if (item.type === 4) {
       payment += item.amount;
     }
   });
 
-  generateForm.currentPayable = payable;
-  generateForm.currentPayment = payment;
+  generateForm.currentPlan = payable;
+  generateForm.currentActually = payment;
+  generateForm.closingBalance = calculateEndBalance(
+    generateForm.openingBalance,
+    generateForm.currentPlan,
+    generateForm.currentActually
+  );
 };
 
 const handlePurchaseSelectionChange = (selection) => {
@@ -342,51 +558,127 @@
 };
 
 const confirmGenerate = () => {
-  const newId = mockData.length > 0 ? Math.max(...mockData.map(item => item.id)) + 1 : 1;
-  const endBalance = calculateEndBalance(generateForm.beginBalance, generateForm.currentPayable, generateForm.currentPayment);
+  if (!canGenerate.value) return;
+  submitLoading.value = true;
+  addAccountStatement(buildAddPayload())
+    .then((res) => {
+      if (res.code === 200) {
+        generateDialogVisible.value = false;
+        ElMessage.success("瀵硅处鍗曠敓鎴愭垚鍔�");
+        pagination.currentPage = 1;
+        getTableData();
+      } else {
+        ElMessage.error(res.msg || "鐢熸垚澶辫触");
+      }
+    })
+    .catch(() => {
+      ElMessage.error("鐢熸垚澶辫触");
+    })
+    .finally(() => {
+      submitLoading.value = false;
+    });
+};
 
-  mockData.unshift({
-    id: newId,
-    statementCode: "DZ" + Date.now(),
-    supplierId: generateForm.supplierId,
-    supplierName: generateForm.supplierName,
-    period: generateForm.period,
-    beginBalance: generateForm.beginBalance,
-    currentPayable: generateForm.currentPayable,
-    currentPayment: generateForm.currentPayment,
-    endBalance,
+const handleDelete = (row) => {
+  ElMessageBox.confirm(`纭鍒犻櫎瀵硅处鍗曘��${row.statementNumber || row.id}銆嶅悧锛焋, "鎻愮ず", {
+    confirmButtonText: "纭畾",
+    cancelButtonText: "鍙栨秷",
+    type: "warning",
+  }).then(() => {
+    deleteAccountStatement([row.id])
+      .then((res) => {
+        if (res.code === 200) {
+          ElMessage.success("鍒犻櫎鎴愬姛");
+          getTableData();
+        } else {
+          ElMessage.error(res.msg || "鍒犻櫎澶辫触");
+        }
+      })
+      .catch(() => {
+        ElMessage.error("鍒犻櫎澶辫触");
+      });
+  });
+};
+
+const buildDetailTableFromApi = (data, statementMonth) => {
+  const details = Array.isArray(data.accountStatementDetails) ? data.accountStatementDetails : [];
+  let runningBalance = Number(data.openingBalance ?? 0);
+  const rows = [
+    {
+      date: statementMonth ?? "",
+      type: "鏈熷垵",
+      code: "-",
+      debit: 0,
+      credit: 0,
+      balance: runningBalance,
+      remark: "鏈熷垵浣欓",
+    },
+  ];
+
+  details.forEach((item) => {
+    const amount = Math.abs(Number(item.amount ?? 0));
+    const type = Number(item.type);
+    let debit = 0;
+    let credit = 0;
+
+    if (type === 2) {
+      credit = amount;
+      runningBalance += amount;
+    } else if (type === 4) {
+      debit = amount;
+      runningBalance -= amount;
+    } else if (type === 5) {
+      credit = -amount;
+      runningBalance -= amount;
+    }
+
+    rows.push({
+      date: item.occurrenceDate ?? "",
+      type: getDetailTypeLabel(type),
+      code: item.receiptNumber ?? "",
+      debit,
+      credit,
+      balance: runningBalance,
+      remark: item.remark ?? "",
+    });
   });
 
-  generateDialogVisible.value = false;
-  ElMessage.success("瀵硅处鍗曠敓鎴愭垚鍔�");
-  getTableData();
+  return rows;
 };
 
 const viewDetail = (row) => {
-  currentSupplier.value = row.supplierName;
-  currentPeriod.value = row.period;
+  const partnerId = row.customerId ?? row.supplierId;
+  if (!partnerId || !row.statementMonth) {
+    ElMessage.warning("缂哄皯渚涘簲鍟嗘垨瀵硅处鏈堜唤锛屾棤娉曟煡璇㈡槑缁�");
+    return;
+  }
 
-  const purchaseInAmount = Math.floor(row.currentPayable * 0.7);
-  const returnAmount = Math.floor(row.currentPayable * 0.1);
-  const firstPayment = Math.floor(row.currentPayment * 0.5);
-  const secondPayment = row.currentPayment - firstPayment;
-
-  let runningBalance = row.beginBalance;
-
-  detailData.value = [
-    { date: row.period + "-01", type: "鏈熷垵", code: "-", debit: 0, credit: 0, balance: runningBalance, remark: "鏈熷垵浣欓" },
-    { date: row.period + "-05", type: "鍏ュ簱", code: "RK2024001", debit: 0, credit: purchaseInAmount, balance: runningBalance += purchaseInAmount, remark: "閲囪喘鍏ュ簱" },
-    { date: row.period + "-10", type: "浠樻", code: "FK2024001", debit: firstPayment, credit: 0, balance: runningBalance -= firstPayment, remark: "鏀粯璐ф" },
-    { date: row.period + "-15", type: "鍏ュ簱", code: "RK2024002", debit: 0, credit: row.currentPayable - purchaseInAmount - returnAmount, balance: runningBalance += (row.currentPayable - purchaseInAmount - returnAmount), remark: "閲囪喘鍏ュ簱" },
-    { date: row.period + "-20", type: "閫�璐�", code: "TH2024001", debit: 0, credit: -returnAmount, balance: runningBalance -= returnAmount, remark: "閲囪喘閫�璐�" },
-    { date: row.period + "-25", type: "浠樻", code: "FK2024002", debit: secondPayment, credit: 0, balance: runningBalance -= secondPayment, remark: "鏀粯璐ф" },
-  ];
-
+  currentSupplier.value = row.supplierName ?? row.customerName ?? "";
+  currentPeriod.value = row.statementMonth ?? "";
+  detailData.value = [];
   detailDialogVisible.value = true;
-};
+  detailLoading.value = true;
 
-const printStatement = (row) => {
-  ElMessage.info(`鎵撳嵃瀵硅处鍗�: ${row.statementCode}`);
+  getAccountStatementDetailsByMonth({
+    accountType: ACCOUNT_TYPE_PAYABLE,
+    customerId: partnerId,
+    statementMonth: row.statementMonth,
+  })
+    .then((res) => {
+      if (res.code === 200) {
+        detailData.value = buildDetailTableFromApi(res.data ?? {}, row.statementMonth);
+      } else {
+        ElMessage.error(res.msg || "鏌ヨ鏄庣粏澶辫触");
+        detailDialogVisible.value = false;
+      }
+    })
+    .catch(() => {
+      ElMessage.error("鏌ヨ鏄庣粏澶辫触");
+      detailDialogVisible.value = false;
+    })
+    .finally(() => {
+      detailLoading.value = false;
+    });
 };
 
 const printDetail = () => {
@@ -394,10 +686,15 @@
 };
 
 const handleOut = () => {
-  ElMessage.success("瀵煎嚭鎴愬姛");
+  proxy.download(
+    "/accountStatement/exportAccountStatement",
+    buildExportParams(),
+    `搴斾粯瀵硅处鍗昣${Date.now()}.xlsx`
+  );
 };
 
 onMounted(() => {
+  getSupplierList();
   getTableData();
 });
 </script>
@@ -415,6 +712,10 @@
 
 .text-danger {
   color: #f56c6c;
+}
+
+.text-primary {
+  color: #409eff;
 }
 
 .statement-header {
@@ -461,9 +762,5 @@
 
 .empty-tip {
   margin-top: 30px;
-}
-
-.text-primary {
-  color: #409eff;
 }
 </style>
diff --git a/src/views/financialManagement/receivable/invoiceApply.vue b/src/views/financialManagement/receivable/invoiceApply.vue
index ac691bc..14fdd67 100644
--- a/src/views/financialManagement/receivable/invoiceApply.vue
+++ b/src/views/financialManagement/receivable/invoiceApply.vue
@@ -72,7 +72,7 @@
           <el-button type="primary" link @click="edit(row)" v-if="isPendingStatus(row.status)">缂栬緫</el-button>
           <el-button type="danger" link @click="handleDelete(row)" v-if="isPendingStatus(row.status)">鍒犻櫎</el-button>
           <el-button type="success" link @click="handleAudit(row)" v-if="isPendingStatus(row.status)">瀹℃牳</el-button>
-          <!-- <el-button type="warning" link @click="handleInvoice(row)" v-if="isApprovedStatus(row.status)">寮�绁�</el-button> -->
+          <el-button type="primary" link @click="openFileDialog(row)" v-if="isApprovedStatus(row.status)">闄勪欢</el-button>
         </template>
       </PIMTable>
     </div>
@@ -119,25 +119,24 @@
           </el-col>
           <el-col :span="12">
             <el-form-item label="鍑哄簱鍗曞彿" prop="outboundBatchNos">
-              <el-select
-                v-model="form.outboundBatchNos"
-                multiple
-                collapse-tags
-                collapse-tags-tooltip
-                filterable
+              <el-input
+                :model-value="outboundBatchDisplayText"
                 placeholder="璇峰厛閫夋嫨瀹㈡埛"
-                style="width: 100%;"
-                :disabled="!form.customerId || isView"
-                :loading="outboundBatchLoading"
-                @change="handleOutboundBatchChange"
+                readonly
+                :disabled="!form.customerId || isEdit || isView"
+                class="outbound-batch-input"
+                @click="handleOutboundInputClick"
               >
-                <el-option
-                  v-for="item in outboundBatchOptions"
-                  :key="item.value"
-                  :label="item.label"
-                  :value="item.value"
-                />
-              </el-select>
+                <template v-if="!isEdit && !isView" #append>
+                  <el-button
+                    :disabled="!form.customerId"
+                    :loading="outboundBatchLoading"
+                    @click.stop="openOutboundSelectDialog"
+                  >
+                    閫夋嫨
+                  </el-button>
+                </template>
+              </el-input>
             </el-form-item>
           </el-col>
         </el-row>
@@ -171,9 +170,9 @@
           <el-col :span="12">
             <el-form-item label="鍙戠エ绫诲瀷" prop="invoiceType">
               <el-select v-model="form.invoiceType" placeholder="璇烽�夋嫨鍙戠エ绫诲瀷" style="width: 100%;" :disabled="isView">
-                <el-option label="澧炲�肩◣涓撶敤鍙戠エ" value="special" />
-                <el-option label="澧炲�肩◣鏅�氬彂绁�" value="normal" />
-                <el-option label="鐢靛瓙鍙戠エ" value="electronic" />
+                <el-option label="澧炲�肩◣涓撶敤鍙戠エ" value="澧炲�肩◣涓撶敤鍙戠エ" />
+                <el-option label="澧炲�肩◣鏅�氬彂绁�" value="澧炲�肩◣鏅�氬彂绁�" />
+                <el-option label="鐢靛瓙鍙戠エ" value="鐢靛瓙鍙戠エ" />
               </el-select>
             </el-form-item>
           </el-col>
@@ -202,11 +201,58 @@
         <el-button @click="closeDialog">鍙栨秷</el-button>
       </template>
     </FormDialog>
+
+    <el-dialog
+      v-model="outboundSelectVisible"
+      title="閫夋嫨鍑哄簱鍗�"
+      width="1200px"
+      append-to-body
+      destroy-on-close
+      :close-on-click-modal="false"
+      @closed="handleOutboundDialogClosed"
+    >
+      <el-table
+        ref="outboundTableRef"
+        v-loading="outboundBatchLoading"
+        :data="outboundBatchList"
+        row-key="id"
+        border
+        stripe
+        max-height="480"
+        @selection-change="handleOutboundDialogSelectionChange"
+      >
+        <el-table-column type="selection" width="55" align="center" />
+        <el-table-column prop="outboundBatches" label="鍑哄簱鍗曞彿" min-width="140" show-overflow-tooltip />
+        <el-table-column prop="customerName" label="瀹㈡埛鍚嶇О" min-width="120" show-overflow-tooltip />
+        <el-table-column prop="productName" label="浜у搧鍚嶇О" min-width="120" show-overflow-tooltip />
+        <el-table-column prop="specificationModel" label="瑙勬牸鍨嬪彿" min-width="140" show-overflow-tooltip />
+        <el-table-column prop="salesContractNo" label="閿�鍞悎鍚屽彿" min-width="140" show-overflow-tooltip />
+        <el-table-column prop="shippingNo" label="鍙戣揣鍗曞彿" min-width="130" show-overflow-tooltip />
+        <el-table-column prop="shippingDate" label="鍙戣揣鏃ユ湡" width="110" align="center" />
+        <el-table-column prop="outboundAmount" label="鍑哄簱閲戦" width="110" align="right">
+          <template #default="{ row }">楼{{ formatMoney(row.outboundAmount) }}</template>
+        </el-table-column>
+        <el-table-column prop="taxRate" label="绋庣巼" width="80" align="center">
+          <template #default="{ row }">{{ row.taxRate }}%</template>
+        </el-table-column>
+      </el-table>
+      <template #footer>
+        <el-button type="primary" @click="confirmOutboundSelection">纭畾</el-button>
+        <el-button @click="outboundSelectVisible = false">鍙栨秷</el-button>
+      </template>
+    </el-dialog>
+
+    <FileList
+      v-if="fileDialogVisible"
+      v-model:visible="fileDialogVisible"
+      record-type="account_invoice_application"
+      :record-id="currentRecordId"
+    />
   </div>
 </template>
 
 <script setup>
-import { ref, reactive, onMounted, getCurrentInstance } from "vue";
+import { ref, reactive, computed, onMounted, nextTick, getCurrentInstance, defineAsyncComponent } from "vue";
 import { ElMessage, ElMessageBox } from "element-plus";
 import FormDialog from "@/components/Dialog/FormDialog.vue";
 import { listCustomer } from "@/api/basicData/customer.js";
@@ -218,6 +264,8 @@
   updateAccountInvoiceApplication,
   deleteAccountInvoiceApplication,
 } from "@/api/financialManagement/invoiceApply.js";
+
+const FileList = defineAsyncComponent(() => import("@/components/Dialog/FileList.vue"));
 
 defineOptions({
   name: "寮�绁ㄧ敵璇�",
@@ -244,10 +292,10 @@
   { label: "瀹㈡埛鍚嶇О", prop: "customerName", width: "180" },
   { label: "寮�绁ㄩ噾棰�", prop: "amount", dataType: "slot", slot: "amount" },
   { label: "绋庣巼", prop: "taxRate", dataType: "slot", slot: "taxRate" },
-  { label: "鍙戠エ绫诲瀷", prop: "invoiceTypeLabel", width: "130" },
+  { label: "鍙戠エ绫诲瀷", prop: "invoiceType", width: "130" },
   { label: "鐢宠鏃ユ湡", prop: "applyDate", width: "120" },
   { label: "瀹℃牳鐘舵��", prop: "status", dataType: "slot", slot: "status", width: "110", align: "center" },
-  { label: "鎿嶄綔", prop: "operation", dataType: "slot", slot: "operation", width: "260", fixed: "right" },
+  { label: "鎿嶄綔", prop: "operation", dataType: "slot", slot: "operation", width: "300", fixed: "right" },
 ];
 
 const dataList = ref([]);
@@ -262,13 +310,18 @@
 
 const closeDialog = () => {
   dialogVisible.value = false;
+  outboundSelectVisible.value = false;
   isView.value = false;
   isEdit.value = false;
 };
 
 const customerList = ref([]);
+const outboundBatchList = ref([]);
 const outboundBatchOptions = ref([]);
 const outboundBatchLoading = ref(false);
+const outboundSelectVisible = ref(false);
+const outboundTableRef = ref(null);
+const dialogOutboundSelection = ref([]);
 
 const getCustomerList = () => {
   listCustomer({ current: -1, size: -1, type: 0 }).then((res) => {
@@ -302,9 +355,13 @@
   });
 };
 
+const isSameOutboundId = (a, b) => String(a) === String(b);
+
 const getSelectedOutboundOptions = () => {
   const selected = form.outboundBatchNos || [];
-  return outboundBatchOptions.value.filter((opt) => selected.includes(opt.value));
+  return outboundBatchOptions.value.filter((opt) =>
+    selected.some((id) => isSameOutboundId(id, opt.value))
+  );
 };
 
 /** 鏍¢獙鎵�閫夊嚭搴撳崟绋庣巼鏄惁涓�鑷达紝涓�鑷村垯鍥炲~ form.taxRate */
@@ -334,18 +391,89 @@
 const syncInvoiceAmount = () => {
   const selected = form.outboundBatchNos || [];
   const sum = outboundBatchOptions.value
-    .filter((opt) => selected.includes(opt.value))
+    .filter((opt) => selected.some((id) => isSameOutboundId(id, opt.value)))
     .reduce((acc, opt) => acc + (Number(opt.outboundAmount) || 0), 0);
   form.amount = sum > 0 ? Number(sum.toFixed(2)) : 0;
 };
 
-const handleOutboundBatchChange = () => {
+const getOutboundRowId = (row) => row?.id ?? row?.stockOutRecordId;
+
+const outboundBatchDisplayText = computed(() => {
+  if (isEdit.value || isView.value) {
+    return form.outboundBatches || "";
+  }
+  if (form.outboundBatches) return form.outboundBatches;
+  const ids = form.outboundBatchNos || [];
+  if (!ids.length) return "";
+  return outboundBatchOptions.value
+    .filter((opt) => ids.some((id) => isSameOutboundId(id, opt.value)))
+    .map((opt) => opt.label)
+    .join("銆�");
+});
+
+const handleOutboundInputClick = () => {
+  if (isEdit.value || isView.value) return;
+  openOutboundSelectDialog();
+};
+
+const restoreOutboundTableSelection = () => {
+  nextTick(() => {
+    const table = outboundTableRef.value;
+    if (!table) return;
+    table.clearSelection();
+    const selectedIds = new Set((form.outboundBatchNos || []).map((id) => String(id)));
+    outboundBatchList.value.forEach((row) => {
+      const rowId = getOutboundRowId(row);
+      if (rowId !== undefined && rowId !== null && selectedIds.has(String(rowId))) {
+        table.toggleRowSelection(row, true);
+      }
+    });
+  });
+};
+
+const openOutboundSelectDialog = () => {
+  if (!form.customerId || isEdit.value || isView.value) return;
+  outboundSelectVisible.value = true;
+  loadOutboundBatches(form.customerId, true).then(() => {
+    restoreOutboundTableSelection();
+  });
+};
+
+const handleOutboundDialogSelectionChange = (selection) => {
+  dialogOutboundSelection.value = selection;
+};
+
+const confirmOutboundSelection = () => {
+  if (dialogOutboundSelection.value.length === 0) {
+    ElMessage.warning("璇疯嚦灏戦�夋嫨涓�鏉″嚭搴撳崟");
+    return;
+  }
+  const prevIds = [...(form.outboundBatchNos || [])];
+  const prevBatches = form.outboundBatches;
+  form.outboundBatchNos = dialogOutboundSelection.value
+    .map((row) => getOutboundRowId(row))
+    .filter((id) => id !== undefined && id !== null);
+  form.outboundBatches = dialogOutboundSelection.value
+    .map((row) => row.outboundBatches ?? row.batchNo ?? row.shippingNo ?? "")
+    .filter(Boolean)
+    .join("銆�");
+  if (!checkTaxRateConsistency()) {
+    form.outboundBatchNos = prevIds;
+    form.outboundBatches = prevBatches;
+    return;
+  }
+  outboundSelectVisible.value = false;
   syncInvoiceAmount();
-  checkTaxRateConsistency();
+  formRef.value?.validateField("outboundBatchNos");
+};
+
+const handleOutboundDialogClosed = () => {
+  dialogOutboundSelection.value = [];
 };
 
 const loadOutboundBatches = (customerId, keepSelected = false) => {
   if (!customerId) {
+    outboundBatchList.value = [];
     outboundBatchOptions.value = [];
     if (!keepSelected) {
       form.outboundBatchNos = [];
@@ -358,12 +486,15 @@
     .then((res) => {
       if (res.code === 200) {
         const list = res.data?.records ?? res.data ?? [];
+        outboundBatchList.value = Array.isArray(list) ? list : [];
         outboundBatchOptions.value = normalizeOutboundBatchOptions(list);
       } else {
+        outboundBatchList.value = [];
         outboundBatchOptions.value = [];
       }
     })
     .catch(() => {
+      outboundBatchList.value = [];
       outboundBatchOptions.value = [];
     })
     .finally(() => {
@@ -377,6 +508,7 @@
 
 const handleCustomerChange = (customerId) => {
   form.outboundBatchNos = [];
+  form.outboundBatches = "";
   form.amount = 0;
   loadOutboundBatches(customerId);
 };
@@ -385,9 +517,10 @@
   applyCode: "",
   customerId: "",
   outboundBatchNos: [],
+  outboundBatches: "",
   amount: 0,
   taxRate: 13,
-  invoiceType: "special",
+  invoiceType: "澧炲�肩◣涓撶敤鍙戠エ",
   applyDate: "",
   content: "",
   remark: "",
@@ -400,12 +533,6 @@
   taxRate: [{ required: true, message: "璇烽�夋嫨绋庣巼", trigger: "change" }],
   invoiceType: [{ required: true, message: "璇烽�夋嫨鍙戠エ绫诲瀷", trigger: "change" }],
   applyDate: [{ required: true, message: "璇烽�夋嫨鐢宠鏃ユ湡", trigger: "change" }],
-};
-
-const INVOICE_TYPE_LABEL_MAP = {
-  special: "澧炲�肩◣涓撶敤鍙戠エ",
-  normal: "澧炲�肩◣鏅�氬彂绁�",
-  electronic: "鐢靛瓙鍙戠エ",
 };
 
 /** 瀹℃牳鐘舵�侊細0寰呭鏍� 1瀹℃牳閫氳繃 2瀹℃牳涓嶉�氳繃 */
@@ -421,8 +548,6 @@
   2: "danger",
 };
 
-const getInvoiceTypeLabel = (type) => INVOICE_TYPE_LABEL_MAP[type] || type || "";
-
 const normalizeStatus = (status) => {
   if (status === undefined || status === null || status === "") return status;
   const num = Number(status);
@@ -432,13 +557,32 @@
 const isPendingStatus = (status) => normalizeStatus(status) === 0;
 const isApprovedStatus = (status) => normalizeStatus(status) === 1;
 
+const fileDialogVisible = ref(false);
+const currentRecordId = ref(0);
+
+const openFileDialog = (row) => {
+  currentRecordId.value = row.id;
+  fileDialogVisible.value = true;
+};
+
+const formatOutboundBatches = (value) => {
+  if (value === undefined || value === null || value === "") return "";
+  if (Array.isArray(value)) return value.filter(Boolean).join("銆�");
+  return String(value)
+    .split(/[,锛宂/)
+    .map((s) => s.trim())
+    .filter(Boolean)
+    .join("銆�");
+};
+
 const normalizeTableRow = (row) => ({
   ...row,
   applyCode: row.invoiceApplicationNo ?? row.applyCode,
   amount: row.invoiceAmount ?? row.amount,
   content: row.invoiceContent ?? row.content,
   status: normalizeStatus(row.status ?? row.auditStatus),
-  invoiceTypeLabel: row.invoiceTypeLabel || getInvoiceTypeLabel(row.invoiceType),
+  stockOutRecordIds: row.stockOutRecordIds ?? row.stockOutRecordId ?? "",
+  outboundBatches: formatOutboundBatches(row.outboundBatches),
 });
 
 const appendFilterParams = (params) => {
@@ -553,14 +697,15 @@
 const fillFormFromRow = (row) => {
   const outboundBatchNos = Array.isArray(row.outboundBatchNos)
     ? row.outboundBatchNos
-    : parseStockOutRecordIds(row.stockOutRecordIds ?? row.outboundBatches);
+    : parseStockOutRecordIds(row.stockOutRecordIds ?? row.stockOutRecordId);
   Object.assign(form, {
     ...row,
     applyCode: row.applyCode ?? row.invoiceApplicationNo ?? "",
-    amount: row.amount ?? row.invoiceAmount,
+    amount: Number(row.amount ?? row.invoiceAmount ?? 0),
     content: row.content ?? row.invoiceContent,
     status: normalizeStatus(row.status ?? row.auditStatus),
     outboundBatchNos,
+    outboundBatches: formatOutboundBatches(row.outboundBatches),
   });
 };
 
@@ -572,13 +717,15 @@
     applyCode: "KP" + Date.now().toString().slice(-8),
     customerId: "",
     outboundBatchNos: [],
+    outboundBatches: "",
     amount: 0,
     taxRate: 13,
-    invoiceType: "special",
-    applyDate: new Date().toISOString().split('T')[0],
+    invoiceType: "澧炲�肩◣涓撶敤鍙戠エ",
+    applyDate: new Date().toISOString().split("T")[0],
     content: "",
     remark: "",
   });
+  outboundBatchList.value = [];
   outboundBatchOptions.value = [];
   dialogVisible.value = true;
 };
@@ -619,7 +766,6 @@
   dialogTitle.value = "缂栬緫寮�绁ㄧ敵璇�";
   fillFormFromRow(row);
   dialogVisible.value = true;
-  loadOutboundBatches(form.customerId, true);
 };
 
 const view = (row) => {
@@ -628,7 +774,6 @@
   dialogTitle.value = "鏌ョ湅寮�绁ㄧ敵璇�";
   fillFormFromRow(row);
   dialogVisible.value = true;
-  loadOutboundBatches(form.customerId, true);
 };
 
 const submitAudit = (row, status) => {
@@ -747,4 +892,10 @@
   color: #409eff;
   font-weight: bold;
 }
+
+.outbound-batch-input:not(.is-disabled) {
+  :deep(.el-input__wrapper) {
+    cursor: pointer;
+  }
+}
 </style>
diff --git a/src/views/financialManagement/receivable/outputInvoice.vue b/src/views/financialManagement/receivable/outputInvoice.vue
index 3e597db..d746aea 100644
--- a/src/views/financialManagement/receivable/outputInvoice.vue
+++ b/src/views/financialManagement/receivable/outputInvoice.vue
@@ -1,19 +1,35 @@
 <template>
   <div class="app-container">
     <el-form :model="filters" :inline="true">
-      <el-form-item label="鍙戠エ浠g爜:">
-        <el-input v-model="filters.invoiceCode" placeholder="璇疯緭鍏ュ彂绁ㄤ唬鐮�" clearable style="width: 200px;" />
-      </el-form-item>
       <el-form-item label="鍙戠エ鍙风爜:">
-        <el-input v-model="filters.invoiceNo" placeholder="璇疯緭鍏ュ彂绁ㄥ彿鐮�" clearable style="width: 200px;" />
+        <el-input v-model="filters.invoiceNumber" placeholder="璇疯緭鍏ュ彂绁ㄥ彿鐮�" clearable style="width: 200px;" />
       </el-form-item>
       <el-form-item label="瀹㈡埛:">
         <el-select v-model="filters.customerId" placeholder="璇烽�夋嫨瀹㈡埛" clearable style="width: 200px;">
-          <el-option v-for="item in customerList" :key="item.id" :label="item.name" :value="item.id" />
+          <el-option v-for="item in customerList" :key="item.id" :label="item.customerName" :value="item.id" />
+        </el-select>
+      </el-form-item>
+      <el-form-item label="寮�绁ㄦ棩鏈�:">
+        <el-date-picker
+          v-model="filters.dateRange"
+          type="daterange"
+          value-format="YYYY-MM-DD"
+          format="YYYY-MM-DD"
+          range-separator="鑷�"
+          start-placeholder="寮�濮嬫棩鏈�"
+          end-placeholder="缁撴潫鏃ユ湡"
+          clearable
+          style="width: 240px;"
+        />
+      </el-form-item>
+      <el-form-item label="鐘舵��:">
+        <el-select v-model="filters.status" placeholder="璇烽�夋嫨鐘舵��" clearable style="width: 150px;">
+          <el-option label="姝e父" :value="0" />
+          <el-option label="浣滃簾" :value="1" />
         </el-select>
       </el-form-item>
       <el-form-item>
-        <el-button type="primary" @click="getTableData">鎼滅储</el-button>
+        <el-button type="primary" @click="onSearch">鎼滅储</el-button>
         <el-button @click="resetFilters">閲嶇疆</el-button>
       </el-form-item>
     </el-form>
@@ -21,13 +37,13 @@
       <div class="actions">
         <div></div>
         <div>
-          <el-button type="primary" @click="add" icon="Plus">褰曞叆鍙戠エ</el-button>
-          <el-button @click="handleImport" icon="Upload">瀵煎叆</el-button>
-          <el-button @click="handleOut" icon="Download">瀵煎嚭</el-button>
+          <!-- <el-button type="primary" @click="add" icon="Plus">褰曞叆鍙戠エ</el-button> -->
+          <el-button type="success" @click="handleExport" icon="Download">瀵煎嚭</el-button>
         </div>
       </div>
       <PIMTable
         rowKey="id"
+        v-loading="tableLoading"
         :column="columns"
         :tableData="dataList"
         :page="{
@@ -46,58 +62,98 @@
         <template #totalAmount="{ row }">
           <span class="text-success">楼{{ formatMoney(row.totalAmount) }}</span>
         </template>
-        <template #invoiceType="{ row }">
-          <el-tag :type="row.invoiceType === 'special' ? 'danger' : 'primary'">{{ row.invoiceTypeLabel }}</el-tag>
+        <template #status="{ row }">
+          <el-tag :type="getStatusType(row.status)" effect="light" round>
+            {{ getStatusLabel(row.status) }}
+          </el-tag>
         </template>
         <template #operation="{ row }">
           <el-button type="primary" link @click="view(row)">鏌ョ湅</el-button>
-          <el-button type="primary" link @click="edit(row)">缂栬緫</el-button>
-          <el-button type="danger" link @click="handleDelete(row)">浣滃簾</el-button>
+          <el-button
+            type="primary"
+            link
+            @click="openFileDialog(row)"
+            v-if="row.accountInvoiceApplicationId"
+          >
+            闄勪欢
+          </el-button>
+          <el-button type="warning" link @click="handleCancel(row)" v-if="isNormalStatus(row.status)">浣滃簾</el-button>
+          <el-button type="danger" link @click="handleDelete(row)">鍒犻櫎</el-button>
         </template>
       </PIMTable>
     </div>
 
-    <FormDialog :title="dialogTitle" v-model="dialogVisible" width="800px" @confirm="submitForm" @cancel="dialogVisible = false">
+    <FormDialog
+      :title="dialogTitle"
+      v-model="dialogVisible"
+      width="800px"
+      :operation-type="isView ? 'detail' : ''"
+      @confirm="submitForm"
+      @cancel="closeDialog"
+    >
       <el-form :model="form" :rules="rules" ref="formRef" label-width="120px">
-        <el-row :gutter="20">
+        <el-row v-if="isView" :gutter="20">
           <el-col :span="12">
-            <el-form-item label="鍙戠エ浠g爜" prop="invoiceCode">
-              <el-input v-model="form.invoiceCode" placeholder="璇疯緭鍏ュ彂绁ㄤ唬鐮�" />
+            <el-form-item label="鐘舵��">
+              <el-tag :type="getStatusType(form.status)" effect="light" round>
+                {{ getStatusLabel(form.status) }}
+              </el-tag>
             </el-form-item>
           </el-col>
+        </el-row>
+        <el-row :gutter="20">
           <el-col :span="12">
             <el-form-item label="鍙戠エ鍙风爜" prop="invoiceNo">
-              <el-input v-model="form.invoiceNo" placeholder="璇疯緭鍏ュ彂绁ㄥ彿鐮�" />
+              <el-input v-model="form.invoiceNo" placeholder="璇疯緭鍏ュ彂绁ㄥ彿鐮�" :disabled="isView" />
             </el-form-item>
           </el-col>
-        </el-row>
-        <el-row :gutter="20">
           <el-col :span="12">
             <el-form-item label="瀹㈡埛" prop="customerId">
-              <el-select v-model="form.customerId" placeholder="璇烽�夋嫨瀹㈡埛" style="width: 100%;">
-                <el-option v-for="item in customerList" :key="item.id" :label="item.name" :value="item.id" />
+              <el-select v-model="form.customerId" placeholder="璇烽�夋嫨瀹㈡埛" style="width: 100%;" :disabled="isView">
+                <el-option v-for="item in customerList" :key="item.id" :label="item.customerName" :value="item.id" />
               </el-select>
-            </el-form-item>
-          </el-col>
-          <el-col :span="12">
-            <el-form-item label="寮�绁ㄦ棩鏈�" prop="invoiceDate">
-              <el-date-picker v-model="form.invoiceDate" type="date" placeholder="閫夋嫨鏃ユ湡" value-format="YYYY-MM-DD" style="width: 100%;" />
             </el-form-item>
           </el-col>
         </el-row>
         <el-row :gutter="20">
           <el-col :span="12">
-            <el-form-item label="鍙戠エ绫诲瀷" prop="invoiceType">
-              <el-select v-model="form.invoiceType" placeholder="璇烽�夋嫨鍙戠エ绫诲瀷" style="width: 100%;" @change="handleInvoiceTypeChange">
-                <el-option label="澧炲�肩◣涓撶敤鍙戠エ" value="special" />
-                <el-option label="澧炲�肩◣鏅�氬彂绁�" value="normal" />
-                <el-option label="鐢靛瓙鍙戠エ" value="electronic" />
-              </el-select>
+            <el-form-item label="寮�绁ㄦ棩鏈�" prop="invoiceDate">
+              <el-date-picker
+                v-model="form.invoiceDate"
+                type="date"
+                placeholder="閫夋嫨鏃ユ湡"
+                value-format="YYYY-MM-DD"
+                style="width: 100%;"
+                :disabled="isView"
+              />
             </el-form-item>
           </el-col>
           <el-col :span="12">
+            <el-form-item label="鍙戠エ绫诲瀷" prop="invoiceType">
+              <el-select
+                v-model="form.invoiceType"
+                placeholder="璇烽�夋嫨鍙戠エ绫诲瀷"
+                style="width: 100%;"
+                :disabled="isView"
+                @change="handleInvoiceTypeChange"
+              >
+                <el-option label="澧炲�肩◣涓撶敤鍙戠エ" value="澧炲�肩◣涓撶敤鍙戠エ" />
+                <el-option label="澧炲�肩◣鏅�氬彂绁�" value="澧炲�肩◣鏅�氬彂绁�" />
+                <el-option label="鐢靛瓙鍙戠エ" value="鐢靛瓙鍙戠エ" />
+              </el-select>
+            </el-form-item>
+          </el-col>
+        </el-row>
+        <el-row :gutter="20">
+          <el-col :span="12">
             <el-form-item label="绋庣巼" prop="taxRate">
-              <el-select v-model="form.taxRate" placeholder="璇烽�夋嫨绋庣巼" style="width: 100%;" @change="calculateTax">
+              <el-select
+                v-model="form.taxRate"
+                placeholder="璇烽�夋嫨绋庣巼"
+                style="width: 100%;"
+                :disabled="isView"
+                @change="calculateTax"
+              >
                 <el-option
                   v-for="dict in tax_rate"
                   :key="dict.value"
@@ -111,7 +167,14 @@
         <el-row :gutter="20">
           <el-col :span="8">
             <el-form-item label="閲戦(涓嶅惈绋�)" prop="amount">
-              <el-input-number v-model="form.amount" :min="0" :precision="2" style="width: 100%;" @change="calculateTax" />
+              <el-input-number
+                v-model="form.amount"
+                :min="0"
+                :precision="2"
+                style="width: 100%;"
+                :disabled="isView"
+                @change="calculateTax"
+              />
             </el-form-item>
           </el-col>
           <el-col :span="8">
@@ -126,24 +189,41 @@
           </el-col>
         </el-row>
         <el-form-item label="鍙戠エ鍐呭" prop="content">
-          <el-input v-model="form.content" type="textarea" :rows="3" placeholder="璇疯緭鍏ュ彂绁ㄥ唴瀹�" />
+          <el-input v-model="form.content" type="textarea" :rows="3" placeholder="璇疯緭鍏ュ彂绁ㄥ唴瀹�" :disabled="isView" />
         </el-form-item>
         <el-form-item label="澶囨敞" prop="remark">
-          <el-input v-model="form.remark" type="textarea" :rows="2" placeholder="璇疯緭鍏ュ娉�" />
+          <el-input v-model="form.remark" type="textarea" :rows="2" placeholder="璇疯緭鍏ュ娉�" :disabled="isView" />
         </el-form-item>
       </el-form>
-      <template #footer>
-        <el-button type="primary" @click="submitForm">纭畾</el-button>
-        <el-button @click="dialogVisible = false">鍙栨秷</el-button>
+      <template v-if="!isView" #footer>
+        <el-button type="primary" :loading="submitLoading" @click="submitForm">纭畾</el-button>
+        <el-button @click="closeDialog">鍙栨秷</el-button>
       </template>
     </FormDialog>
+
+    <FileList
+      v-if="fileDialogVisible"
+      v-model:visible="fileDialogVisible"
+      record-type="account_invoice_application"
+      :record-id="currentRecordId"
+      :editable="false"
+    />
   </div>
 </template>
 
 <script setup>
-import { ref, reactive, onMounted, computed, getCurrentInstance } from "vue";
+import { ref, reactive, onMounted, getCurrentInstance, defineAsyncComponent } from "vue";
 import { ElMessage, ElMessageBox } from "element-plus";
 import FormDialog from "@/components/Dialog/FormDialog.vue";
+import { listCustomer } from "@/api/basicData/customer.js";
+import {
+  addAccountSalesInvoice,
+  listPageAccountSalesInvoice,
+  cancelAccountSalesInvoice,
+  deleteAccountSalesInvoice,
+} from "@/api/financialManagement/accountSalesInvoice.js";
+
+const FileList = defineAsyncComponent(() => import("@/components/Dialog/FileList.vue"));
 
 defineOptions({
   name: "閿�椤瑰彂绁�",
@@ -153,9 +233,10 @@
 const { tax_rate } = proxy.useDict("tax_rate");
 
 const filters = reactive({
-  invoiceCode: "",
-  invoiceNo: "",
+  invoiceNumber: "",
   customerId: "",
+  dateRange: [],
+  status: "",
 });
 
 const pagination = reactive({
@@ -165,47 +246,76 @@
 });
 
 const columns = [
-  { label: "鍙戠エ浠g爜", prop: "invoiceCode", width: "130" },
-  { label: "鍙戠エ鍙风爜", prop: "invoiceNo", width: "120" },
+  { label: "鍙戠エ鍙风爜", prop: "invoiceNo", width: "140" },
   { label: "瀹㈡埛鍚嶇О", prop: "customerName", width: "180" },
   { label: "寮�绁ㄦ棩鏈�", prop: "invoiceDate", width: "120" },
-  { label: "閲戦", prop: "amount", slot: "amount" },
-  { label: "绋庨", prop: "taxAmount", slot: "taxAmount" },
-  { label: "浠风◣鍚堣", prop: "totalAmount", slot: "totalAmount" },
-  { label: "鍙戠エ绫诲瀷", prop: "invoiceType", slot: "invoiceType" },
-  { label: "鎿嶄綔", prop: "operation", slot: "operation", width: "180", fixed: "right" },
+  { label: "閲戦", prop: "amount", dataType: "slot", slot: "amount" },
+  { label: "绋庨", prop: "taxAmount", dataType: "slot", slot: "taxAmount" },
+  { label: "浠风◣鍚堣", prop: "totalAmount", dataType: "slot", slot: "totalAmount" },
+  { label: "鍙戠エ绫诲瀷", prop: "invoiceType", width: "130" },
+  { label: "鐘舵��", prop: "status", dataType: "slot", slot: "status", width: "90", align: "center" },
+  { label: "鎿嶄綔", prop: "operation", dataType: "slot", slot: "operation", width: "260", fixed: "right" },
 ];
 
 const dataList = ref([]);
+const tableLoading = ref(false);
 const dialogVisible = ref(false);
 const dialogTitle = ref("");
 const formRef = ref(null);
-const isEdit = ref(false);
-const currentId = ref(null);
+const isView = ref(false);
+const submitLoading = ref(false);
 
-const customerList = [
-  { id: 1, name: "鍖椾含绉戞妧鏈夐檺鍏徃" },
-  { id: 2, name: "涓婃捣璐告槗鍏徃" },
-  { id: 3, name: "骞垮窞瀹炰笟鏈夐檺鍏徃" },
-  { id: 4, name: "娣卞湷鐢靛瓙鍏徃" },
-];
+const customerList = ref([]);
+const fileDialogVisible = ref(false);
+const currentRecordId = ref(0);
+
+const openFileDialog = (row) => {
+  if (!row.accountInvoiceApplicationId) {
+    ElMessage.warning("鏈叧鑱斿紑绁ㄧ敵璇凤紝鏃犳硶鏌ョ湅闄勪欢");
+    return;
+  }
+  currentRecordId.value = row.accountInvoiceApplicationId;
+  fileDialogVisible.value = true;
+};
+
+/** 鐘舵�侊細0姝e父 1浣滃簾 */
+const STATUS_LABEL_MAP = { 0: "姝e父", 1: "浣滃簾" };
+const STATUS_TYPE_MAP = { 0: "success", 1: "info" };
+
+const normalizeStatus = (status) => {
+  if (status === undefined || status === null || status === "") return 0;
+  const num = Number(status);
+  return Number.isNaN(num) ? 0 : num;
+};
+
+const isNormalStatus = (status) => normalizeStatus(status) === 0;
+
+const getStatusLabel = (status) => {
+  const num = normalizeStatus(status);
+  return STATUS_LABEL_MAP[num] ?? "姝e父";
+};
+
+const getStatusType = (status) => {
+  const num = normalizeStatus(status);
+  return STATUS_TYPE_MAP[num] ?? "success";
+};
 
 const form = reactive({
-  invoiceCode: "",
   invoiceNo: "",
   customerId: "",
   invoiceDate: "",
-  invoiceType: "special",
+  invoiceType: "澧炲�肩◣涓撶敤鍙戠エ",
   taxRate: 13,
   amount: 0,
   taxAmount: 0,
   totalAmount: 0,
   content: "",
   remark: "",
+  accountInvoiceApplicationId: undefined,
+  storageAttachmentId: undefined,
 });
 
 const rules = {
-  invoiceCode: [{ required: true, message: "璇疯緭鍏ュ彂绁ㄤ唬鐮�", trigger: "blur" }],
   invoiceNo: [{ required: true, message: "璇疯緭鍏ュ彂绁ㄥ彿鐮�", trigger: "blur" }],
   customerId: [{ required: true, message: "璇烽�夋嫨瀹㈡埛", trigger: "change" }],
   invoiceDate: [{ required: true, message: "璇烽�夋嫨寮�绁ㄦ棩鏈�", trigger: "change" }],
@@ -213,12 +323,6 @@
   taxRate: [{ required: true, message: "璇烽�夋嫨绋庣巼", trigger: "change" }],
   amount: [{ required: true, message: "璇疯緭鍏ラ噾棰�", trigger: "blur" }],
 };
-
-const mockData = [
-  { id: 1, invoiceCode: "0440021001", invoiceNo: "12345678", customerId: 1, customerName: "鍖椾含绉戞妧鏈夐檺鍏徃", invoiceDate: "2024-01-15", amount: 5000, taxRate: 13, taxAmount: 650, totalAmount: 5650, invoiceType: "special", invoiceTypeLabel: "澧炲�肩◣涓撶敤鍙戠エ", content: "杞欢鏈嶅姟璐�", remark: "" },
-  { id: 2, invoiceCode: "0440021002", invoiceNo: "87654321", customerId: 2, customerName: "涓婃捣璐告槗鍏徃", invoiceDate: "2024-01-16", amount: 8000, taxRate: 13, taxAmount: 1040, totalAmount: 9040, invoiceType: "normal", invoiceTypeLabel: "澧炲�肩◣鏅�氬彂绁�", content: "鍟嗗搧閿�鍞�", remark: "" },
-  { id: 3, invoiceCode: "0440021003", invoiceNo: "11112222", customerId: 3, customerName: "骞垮窞瀹炰笟鏈夐檺鍏徃", invoiceDate: "2024-01-18", amount: 12000, taxRate: 6, taxAmount: 720, totalAmount: 12720, invoiceType: "electronic", invoiceTypeLabel: "鐢靛瓙鍙戠エ", content: "鎶�鏈湇鍔¤垂", remark: "" },
-];
 
 const formatMoney = (value) => {
   if (value === undefined || value === null) return "0.00";
@@ -231,33 +335,142 @@
 };
 
 const handleInvoiceTypeChange = () => {
-  if (form.invoiceType === "special") {
-    form.taxRate = 13;
-  } else {
-    form.taxRate = 13;
-  }
   calculateTax();
 };
 
-const getTableData = () => {
-  let result = [...mockData];
-  if (filters.invoiceCode) {
-    result = result.filter(item => item.invoiceCode.includes(filters.invoiceCode));
-  }
-  if (filters.invoiceNo) {
-    result = result.filter(item => item.invoiceNo.includes(filters.invoiceNo));
+const normalizeTableRow = (row) => ({
+  ...row,
+  invoiceNo: row.invoiceNumber ?? row.invoiceNo,
+  invoiceDate: row.issueDate ?? row.invoiceDate,
+  amount: row.taxExclusivelPrice ?? row.amount,
+  taxAmount: row.taxPrice ?? row.taxAmount,
+  totalAmount: row.taxInclusivePrice ?? row.totalAmount,
+  content: row.invoiceContent ?? row.content,
+  status: normalizeStatus(row.status),
+});
+
+const fillFormFromRow = (row) => {
+  Object.assign(form, {
+    invoiceNo: row.invoiceNo ?? row.invoiceNumber ?? "",
+    customerId: row.customerId,
+    invoiceDate: row.invoiceDate ?? row.issueDate ?? "",
+    invoiceType: row.invoiceType ?? "澧炲�肩◣涓撶敤鍙戠エ",
+    taxRate: row.taxRate ?? 13,
+    amount: row.amount ?? row.taxExclusivelPrice ?? 0,
+    taxAmount: row.taxAmount ?? row.taxPrice ?? 0,
+    totalAmount: row.totalAmount ?? row.taxInclusivePrice ?? 0,
+    content: row.content ?? row.invoiceContent ?? "",
+    remark: row.remark ?? "",
+    accountInvoiceApplicationId: row.accountInvoiceApplicationId,
+    storageAttachmentId: row.storageAttachmentId,
+    status: normalizeStatus(row.status),
+  });
+};
+
+const buildCancelPayload = (row) => ({
+  id: row.id,
+  accountInvoiceApplicationId: row.accountInvoiceApplicationId,
+  invoiceNumber: row.invoiceNumber ?? row.invoiceNo,
+  taxRate: row.taxRate,
+  invoiceType: row.invoiceType,
+  issueDate: row.issueDate ?? row.invoiceDate,
+  taxExclusivelPrice: row.taxExclusivelPrice ?? row.amount,
+  taxPrice: row.taxPrice ?? row.taxAmount,
+  taxInclusivePrice: row.taxInclusivePrice ?? row.totalAmount,
+  remark: row.remark ?? "",
+  invoiceContent: row.invoiceContent ?? row.content,
+  customerId: row.customerId,
+  storageAttachmentId: row.storageAttachmentId,
+  status: 1,
+});
+
+const buildSubmitPayload = () => ({
+  invoiceNumber: form.invoiceNo,
+  customerId: form.customerId,
+  issueDate: form.invoiceDate,
+  invoiceType: form.invoiceType,
+  taxRate: form.taxRate,
+  taxExclusivelPrice: form.amount,
+  taxPrice: form.taxAmount,
+  taxInclusivePrice: form.totalAmount,
+  invoiceContent: form.content,
+  remark: form.remark || "",
+  accountInvoiceApplicationId: form.accountInvoiceApplicationId,
+  storageAttachmentId: form.storageAttachmentId,
+});
+
+const getCustomerList = () => {
+  listCustomer({ current: -1, size: -1, type: 0 }).then((res) => {
+    if (res.code === 200) {
+      customerList.value = res.data?.records || [];
+    }
+  });
+};
+
+const appendFilterParams = (params) => {
+  if (filters.invoiceNumber) {
+    params.invoiceNumber = filters.invoiceNumber;
   }
   if (filters.customerId) {
-    result = result.filter(item => item.customerId === filters.customerId);
+    params.customerId = filters.customerId;
   }
-  pagination.total = result.length;
-  dataList.value = result.slice((pagination.currentPage - 1) * pagination.pageSize, pagination.currentPage * pagination.pageSize);
+  if (filters.dateRange?.length === 2) {
+    params.startDate = filters.dateRange[0];
+    params.endDate = filters.dateRange[1];
+  }
+  if (filters.status !== "" && filters.status != null) {
+    params.status = filters.status;
+  }
+  return params;
+};
+
+const buildListParams = () =>
+  appendFilterParams({
+    current: pagination.currentPage,
+    size: pagination.pageSize,
+  });
+
+const buildExportParams = () => appendFilterParams({});
+
+const handleExport = () => {
+  const params = buildExportParams();
+  proxy.download("/accountSalesInvoice/exportAccountSalesInvoice", params, `閿�椤瑰彂绁╛${Date.now()}.xlsx`);
+};
+
+const getTableData = () => {
+  tableLoading.value = true;
+  listPageAccountSalesInvoice(buildListParams())
+    .then((res) => {
+      if (res.code === 200) {
+        const records = res.data?.records ?? [];
+        dataList.value = records.map(normalizeTableRow);
+        pagination.total = res.data?.total ?? 0;
+      } else {
+        dataList.value = [];
+        pagination.total = 0;
+        ElMessage.error(res.msg || "鏌ヨ澶辫触");
+      }
+    })
+    .catch(() => {
+      dataList.value = [];
+      pagination.total = 0;
+      ElMessage.error("鏌ヨ澶辫触");
+    })
+    .finally(() => {
+      tableLoading.value = false;
+    });
+};
+
+const onSearch = () => {
+  pagination.currentPage = 1;
+  getTableData();
 };
 
 const resetFilters = () => {
-  filters.invoiceCode = "";
-  filters.invoiceNo = "";
+  filters.invoiceNumber = "";
   filters.customerId = "";
+  filters.dateRange = [];
+  filters.status = "";
   pagination.currentPage = 1;
   getTableData();
 };
@@ -268,83 +481,105 @@
   getTableData();
 };
 
+const closeDialog = () => {
+  dialogVisible.value = false;
+  isView.value = false;
+};
+
 const add = () => {
-  isEdit.value = false;
+  isView.value = false;
   dialogTitle.value = "褰曞叆鍙戠エ";
   Object.assign(form, {
-    invoiceCode: "",
     invoiceNo: "",
     customerId: "",
-    invoiceDate: new Date().toISOString().split('T')[0],
-    invoiceType: "special",
+    invoiceDate: new Date().toISOString().split("T")[0],
+    invoiceType: "澧炲�肩◣涓撶敤鍙戠エ",
     taxRate: 13,
     amount: 0,
     taxAmount: 0,
     totalAmount: 0,
     content: "",
     remark: "",
+    accountInvoiceApplicationId: undefined,
+    storageAttachmentId: undefined,
   });
-  dialogVisible.value = true;
-};
-
-const edit = (row) => {
-  isEdit.value = true;
-  currentId.value = row.id;
-  dialogTitle.value = "缂栬緫鍙戠エ";
-  Object.assign(form, row);
   dialogVisible.value = true;
 };
 
 const view = (row) => {
-  ElMessage.info(`鏌ョ湅鍙戠エ: ${row.invoiceCode}-${row.invoiceNo}`);
+  isView.value = true;
+  dialogTitle.value = "鏌ョ湅鍙戠エ";
+  fillFormFromRow(row);
+  dialogVisible.value = true;
 };
 
-const handleDelete = (row) => {
-  ElMessageBox.confirm("纭浣滃簾璇ュ彂绁ㄥ悧锛�", "鎻愮ず", {
+const handleCancel = (row) => {
+  ElMessageBox.confirm(`纭浣滃簾鍙戠エ銆�${row.invoiceNo ?? row.invoiceNumber}銆嶅悧锛焋, "浣滃簾纭", {
     confirmButtonText: "纭畾",
     cancelButtonText: "鍙栨秷",
     type: "warning",
   }).then(() => {
-    const index = mockData.findIndex(item => item.id === row.id);
-    if (index !== -1) {
-      mockData.splice(index, 1);
-    }
-    ElMessage.success("浣滃簾鎴愬姛");
-    getTableData();
+    cancelAccountSalesInvoice(buildCancelPayload(row))
+      .then((res) => {
+        if (res.code === 200) {
+          ElMessage.success("浣滃簾鎴愬姛");
+          getTableData();
+        } else {
+          ElMessage.error(res.msg || "浣滃簾澶辫触");
+        }
+      })
+      .catch(() => {
+        ElMessage.error("浣滃簾澶辫触");
+      });
   });
 };
 
-const handleImport = () => {
-  ElMessage.info("瀵煎叆鍔熻兘");
-};
-
-const handleOut = () => {
-  ElMessage.success("瀵煎嚭鎴愬姛");
+const handleDelete = (row) => {
+  ElMessageBox.confirm(`纭鍒犻櫎鍙戠エ銆�${row.invoiceNo ?? row.invoiceNumber}銆嶅悧锛熷垹闄ゅ悗涓嶅彲鎭㈠銆俙, "鍒犻櫎纭", {
+    confirmButtonText: "纭畾",
+    cancelButtonText: "鍙栨秷",
+    type: "warning",
+  }).then(() => {
+    deleteAccountSalesInvoice([row.id])
+      .then((res) => {
+        if (res.code === 200) {
+          ElMessage.success("鍒犻櫎鎴愬姛");
+          getTableData();
+        } else {
+          ElMessage.error(res.msg || "鍒犻櫎澶辫触");
+        }
+      })
+      .catch(() => {
+        ElMessage.error("鍒犻櫎澶辫触");
+      });
+  });
 };
 
 const submitForm = () => {
   formRef.value.validate((valid) => {
-    if (valid) {
-      const customer = customerList.find(item => item.id === form.customerId);
-      const invoiceTypeMap = { special: "澧炲�肩◣涓撶敤鍙戠エ", normal: "澧炲�肩◣鏅�氬彂绁�", electronic: "鐢靛瓙鍙戠エ" };
-      if (isEdit.value) {
-        const index = mockData.findIndex(item => item.id === currentId.value);
-        if (index !== -1) {
-          mockData[index] = { ...mockData[index], ...form, customerName: customer?.name, invoiceTypeLabel: invoiceTypeMap[form.invoiceType] };
+    if (!valid) return;
+    submitLoading.value = true;
+    addAccountSalesInvoice(buildSubmitPayload())
+      .then((res) => {
+        if (res.code === 200) {
+          ElMessage.success("褰曞叆鎴愬姛");
+          closeDialog();
+          getTableData();
+        } else {
+          ElMessage.error(res.msg || "褰曞叆澶辫触");
         }
-        ElMessage.success("缂栬緫鎴愬姛");
-      } else {
-        const newId = mockData.length > 0 ? Math.max(...mockData.map(item => item.id)) + 1 : 1;
-        mockData.push({ id: newId, ...form, customerName: customer?.name, invoiceTypeLabel: invoiceTypeMap[form.invoiceType] });
-        ElMessage.success("褰曞叆鎴愬姛");
-      }
-      dialogVisible.value = false;
-      getTableData();
-    }
+      })
+      .catch(() => {
+        ElMessage.error("褰曞叆澶辫触");
+      })
+      .finally(() => {
+        submitLoading.value = false;
+      });
   });
 };
 
 onMounted(() => {
+  getCustomerList();
   getTableData();
 });
 </script>
diff --git a/src/views/financialManagement/receivable/receipt.vue b/src/views/financialManagement/receivable/receipt.vue
index 2bbbb96..f19da42 100644
--- a/src/views/financialManagement/receivable/receipt.vue
+++ b/src/views/financialManagement/receivable/receipt.vue
@@ -2,40 +2,54 @@
   <div class="app-container">
     <el-form :model="filters" :inline="true">
       <el-form-item label="鏀舵鍗曞彿:">
-        <el-input v-model="filters.receiptCode" placeholder="璇疯緭鍏ユ敹娆惧崟鍙�" clearable style="width: 200px;" />
+        <el-input v-model="filters.collectionNumber" placeholder="璇疯緭鍏ユ敹娆惧崟鍙�" clearable style="width: 200px;" />
       </el-form-item>
       <el-form-item label="瀹㈡埛:">
-        <el-select v-model="filters.customerId" placeholder="璇烽�夋嫨瀹㈡埛" clearable style="width: 200px;">
-          <el-option v-for="item in customerList" :key="item.id" :label="item.name" :value="item.id" />
+        <el-select v-model="filters.customerId" placeholder="璇烽�夋嫨瀹㈡埛" clearable filterable style="width: 200px;">
+          <el-option v-for="item in customerList" :key="item.id" :label="item.customerName" :value="item.id" />
         </el-select>
       </el-form-item>
       <el-form-item label="鏀舵鏂瑰紡:">
-        <el-select v-model="filters.receiptMethod" placeholder="璇烽�夋嫨鏀舵鏂瑰紡" clearable style="width: 150px;">
-          <el-option label="閾惰杞处" value="bank_transfer" />
-          <el-option label="鐜伴噾" value="cash" />
-          <el-option label="鏀エ" value="check" />
-          <el-option label="姹囩エ" value="draft" />
-          <el-option label="鏀粯瀹�" value="alipay" />
-          <el-option label="寰俊" value="wechat" />
+        <el-select v-model="filters.collectionMethod" placeholder="璇烽�夋嫨鏀舵鏂瑰紡" clearable style="width: 150px;">
+          <el-option
+            v-for="item in payment_methods"
+            :key="item.value"
+            :label="item.label"
+            :value="item.value"
+          />
         </el-select>
       </el-form-item>
+      <el-form-item label="鏀舵鏃ユ湡:">
+        <el-date-picker
+          v-model="filters.dateRange"
+          type="daterange"
+          value-format="YYYY-MM-DD"
+          format="YYYY-MM-DD"
+          range-separator="鑷�"
+          start-placeholder="寮�濮嬫棩鏈�"
+          end-placeholder="缁撴潫鏃ユ湡"
+          clearable
+          style="width: 240px;"
+        />
+      </el-form-item>
       <el-form-item>
-        <el-button type="primary" @click="getTableData">鎼滅储</el-button>
+        <el-button type="primary" @click="onSearch">鎼滅储</el-button>
         <el-button @click="resetFilters">閲嶇疆</el-button>
       </el-form-item>
     </el-form>
     <div class="table_list">
       <div class="actions">
         <div>
-          <el-statistic title="鏈湡鏀舵鍚堣" :value="totalReceiptAmount" precision="2" prefix="楼" />
+          <el-statistic title="鏈〉鏀舵鍚堣" :value="totalReceiptAmount" :precision="2" prefix="楼" />
         </div>
         <div>
           <el-button type="primary" @click="add" icon="Plus">鏂板鏀舵</el-button>
-          <el-button @click="handleOut" icon="Download">瀵煎嚭</el-button>
+          <el-button type="success" @click="handleExport" icon="Download">瀵煎嚭</el-button>
         </div>
       </div>
       <PIMTable
         rowKey="id"
+        v-loading="tableLoading"
         :column="columns"
         :tableData="dataList"
         :page="{
@@ -49,97 +63,192 @@
           <span class="text-success">楼{{ formatMoney(row.amount) }}</span>
         </template>
         <template #receiptMethod="{ row }">
-          <el-tag>{{ getReceiptMethodLabel(row.receiptMethod) }}</el-tag>
-        </template>
-        <template #status="{ row }">
-          <el-tag :type="row.status === 'confirmed' ? 'success' : 'warning'">{{ row.status === 'confirmed' ? '宸茬‘璁�' : '寰呯‘璁�' }}</el-tag>
+          <span>{{ getReceiptMethodLabel(row.receiptMethod) }}</span>
         </template>
         <template #operation="{ row }">
           <el-button type="primary" link @click="view(row)">鏌ョ湅</el-button>
-          <el-button type="primary" link @click="edit(row)" v-if="row.status === 'pending'">缂栬緫</el-button>
-          <el-button type="success" link @click="handleConfirm(row)" v-if="row.status === 'pending'">纭</el-button>
-          <el-button type="danger" link @click="handleDelete(row)" v-if="row.status === 'pending'">鍒犻櫎</el-button>
+          <el-button type="primary" link @click="edit(row)">缂栬緫</el-button>
+          <el-button type="danger" link @click="handleDelete(row)">鍒犻櫎</el-button>
         </template>
       </PIMTable>
     </div>
 
-    <FormDialog :title="dialogTitle" v-model="dialogVisible" width="800px" @confirm="submitForm" @cancel="dialogVisible = false">
+    <FormDialog
+      :title="dialogTitle"
+      v-model="dialogVisible"
+      width="800px"
+      :operation-type="isView ? 'detail' : ''"
+      @confirm="submitForm"
+      @cancel="closeDialog"
+    >
       <el-form :model="form" :rules="rules" ref="formRef" label-width="120px">
         <el-row :gutter="20">
-          <el-col :span="12">
+          <el-col :span="24">
             <el-form-item label="鏀舵鍗曞彿" prop="receiptCode">
               <el-input v-model="form.receiptCode" placeholder="绯荤粺鑷姩鐢熸垚" disabled />
             </el-form-item>
           </el-col>
+        </el-row>
+        <el-row :gutter="20">
           <el-col :span="12">
             <el-form-item label="瀹㈡埛" prop="customerId">
-              <el-select v-model="form.customerId" placeholder="璇烽�夋嫨瀹㈡埛" style="width: 100%;" :disabled="isEdit">
-                <el-option v-for="item in customerList" :key="item.id" :label="item.name" :value="item.id" />
+              <el-select
+                v-model="form.customerId"
+                placeholder="璇烽�夋嫨瀹㈡埛"
+                style="width: 100%;"
+                :disabled="isEdit || isView"
+                filterable
+                @change="handleCustomerChange"
+              >
+                <el-option v-for="item in customerList" :key="item.id" :label="item.customerName" :value="item.id" />
               </el-select>
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="鍏宠仈鍗曟嵁" prop="stockOutRecordIds">
+              <el-input
+                :model-value="outboundBatchDisplayText"
+                placeholder="璇峰厛閫夋嫨瀹㈡埛"
+                readonly
+                :disabled="!form.customerId || isEdit || isView"
+                class="outbound-batch-input"
+                @click="handleOutboundInputClick"
+              >
+                <template v-if="!isEdit && !isView" #append>
+                  <el-button
+                    :disabled="!form.customerId"
+                    :loading="outboundBatchLoading"
+                    @click.stop="openOutboundSelectDialog"
+                  >
+                    閫夋嫨
+                  </el-button>
+                </template>
+              </el-input>
             </el-form-item>
           </el-col>
         </el-row>
         <el-row :gutter="20">
           <el-col :span="12">
             <el-form-item label="鏀舵鏃ユ湡" prop="receiptDate">
-              <el-date-picker v-model="form.receiptDate" type="date" placeholder="閫夋嫨鏃ユ湡" value-format="YYYY-MM-DD" style="width: 100%;" />
+              <el-date-picker
+                v-model="form.receiptDate"
+                type="date"
+                placeholder="閫夋嫨鏃ユ湡"
+                value-format="YYYY-MM-DD"
+                style="width: 100%;"
+                :disabled="isView"
+              />
             </el-form-item>
           </el-col>
           <el-col :span="12">
             <el-form-item label="鏀舵閲戦" prop="amount">
-              <el-input-number v-model="form.amount" :min="0" :precision="2" style="width: 100%;" />
+              <el-input-number
+                v-model="form.amount"
+                :min="0"
+                :precision="2"
+                style="width: 100%;"
+                :disabled="isView"
+                placeholder="鏍规嵁鍏宠仈鍗曟嵁鑷姩姹囨�伙紝鍙慨鏀�"
+              />
             </el-form-item>
           </el-col>
         </el-row>
         <el-row :gutter="20">
           <el-col :span="12">
             <el-form-item label="鏀舵鏂瑰紡" prop="receiptMethod">
-              <el-select v-model="form.receiptMethod" placeholder="璇烽�夋嫨鏀舵鏂瑰紡" style="width: 100%;">
-                <el-option label="閾惰杞处" value="bank_transfer" />
-                <el-option label="鐜伴噾" value="cash" />
-                <el-option label="鏀エ" value="check" />
-                <el-option label="姹囩エ" value="draft" />
-                <el-option label="鏀粯瀹�" value="alipay" />
-                <el-option label="寰俊" value="wechat" />
+              <el-select
+                v-model="form.receiptMethod"
+                placeholder="璇烽�夋嫨鏀舵鏂瑰紡"
+                style="width: 100%;"
+                :disabled="isView"
+              >
+                <el-option
+                  v-for="item in payment_methods"
+                  :key="item.value"
+                  :label="item.label"
+                  :value="item.value"
+                />
               </el-select>
             </el-form-item>
           </el-col>
-          <el-col :span="12">
-            <el-form-item label="閾惰璐﹀彿" prop="bankAccount" v-if="form.receiptMethod === 'bank_transfer'">
-              <el-input v-model="form.bankAccount" placeholder="璇疯緭鍏ラ摱琛岃处鍙�" />
-            </el-form-item>
-          </el-col>
         </el-row>
-        <el-form-item label="鍏宠仈鍗曟嵁" prop="relatedDocs">
-          <el-select v-model="form.relatedDocs" multiple placeholder="璇烽�夋嫨鍏宠仈鍗曟嵁" style="width: 100%;">
-            <el-option v-for="item in outList" :key="item.outCode" :label="item.outCode" :value="item.outCode" />
-          </el-select>
-        </el-form-item>
         <el-form-item label="澶囨敞" prop="remark">
-          <el-input v-model="form.remark" type="textarea" :rows="3" placeholder="璇疯緭鍏ュ娉�" />
+          <el-input v-model="form.remark" type="textarea" :rows="3" placeholder="璇疯緭鍏ュ娉�" :disabled="isView" />
         </el-form-item>
       </el-form>
-      <template #footer>
-        <el-button type="primary" @click="submitForm">纭畾</el-button>
-        <el-button @click="dialogVisible = false">鍙栨秷</el-button>
+      <template v-if="!isView" #footer>
+        <el-button type="primary" :loading="submitLoading" @click="submitForm">纭畾</el-button>
+        <el-button @click="closeDialog">鍙栨秷</el-button>
       </template>
     </FormDialog>
+
+    <el-dialog
+      v-model="outboundSelectVisible"
+      title="閫夋嫨鍏宠仈鍗曟嵁"
+      width="1200px"
+      append-to-body
+      destroy-on-close
+      :close-on-click-modal="false"
+      @closed="handleOutboundDialogClosed"
+    >
+      <el-table
+        ref="outboundTableRef"
+        v-loading="outboundBatchLoading"
+        :data="outboundBatchList"
+        row-key="id"
+        border
+        stripe
+        max-height="480"
+        @selection-change="handleOutboundDialogSelectionChange"
+      >
+        <el-table-column type="selection" width="55" align="center" />
+        <el-table-column prop="outboundBatches" label="鍑哄簱鍗曞彿" min-width="140" show-overflow-tooltip />
+        <el-table-column prop="customerName" label="瀹㈡埛鍚嶇О" min-width="120" show-overflow-tooltip />
+        <el-table-column prop="productName" label="浜у搧鍚嶇О" min-width="120" show-overflow-tooltip />
+        <el-table-column prop="specificationModel" label="瑙勬牸鍨嬪彿" min-width="140" show-overflow-tooltip />
+        <el-table-column prop="salesContractNo" label="閿�鍞悎鍚屽彿" min-width="140" show-overflow-tooltip />
+        <el-table-column prop="shippingNo" label="鍙戣揣鍗曞彿" min-width="130" show-overflow-tooltip />
+        <el-table-column prop="shippingDate" label="鍙戣揣鏃ユ湡" width="110" align="center" />
+        <el-table-column prop="outboundAmount" label="鍑哄簱閲戦" width="110" align="right">
+          <template #default="{ row }">楼{{ formatMoney(row.outboundAmount) }}</template>
+        </el-table-column>
+        <el-table-column prop="taxRate" label="绋庣巼" width="80" align="center">
+          <template #default="{ row }">{{ row.taxRate }}%</template>
+        </el-table-column>
+      </el-table>
+      <template #footer>
+        <el-button type="primary" @click="confirmOutboundSelection">纭畾</el-button>
+        <el-button @click="outboundSelectVisible = false">鍙栨秷</el-button>
+      </template>
+    </el-dialog>
   </div>
 </template>
 
 <script setup>
-import { ref, reactive, onMounted, computed } from "vue";
+import { ref, reactive, computed, onMounted, nextTick, getCurrentInstance } from "vue";
 import { ElMessage, ElMessageBox } from "element-plus";
 import FormDialog from "@/components/Dialog/FormDialog.vue";
+import { listCustomer } from "@/api/basicData/customer.js";
+import {
+  getOutboundBatchesByCustomer,
+  addAccountSalesCollection,
+  listPageAccountSalesCollection,
+  updateAccountSalesCollection,
+  deleteAccountSalesCollection,
+} from "@/api/financialManagement/accountSalesCollection.js";
 
 defineOptions({
   name: "鏀舵鍗�",
 });
 
+const { proxy } = getCurrentInstance();
+const { payment_methods } = proxy.useDict("payment_methods");
+
 const filters = reactive({
-  receiptCode: "",
+  collectionNumber: "",
   customerId: "",
-  receiptMethod: "",
+  collectionMethod: "",
+  dateRange: [],
 });
 
 const pagination = reactive({
@@ -152,97 +261,365 @@
   { label: "鏀舵鍗曞彿", prop: "receiptCode", width: "150" },
   { label: "瀹㈡埛鍚嶇О", prop: "customerName", width: "180" },
   { label: "鏀舵鏃ユ湡", prop: "receiptDate", width: "120" },
-  { label: "鏀舵閲戦", prop: "amount", slot: "amount" },
-  { label: "鏀舵鏂瑰紡", prop: "receiptMethod", slot: "receiptMethod" },
-  { label: "鐘舵��", prop: "status", slot: "status" },
+  { label: "鏀舵閲戦", prop: "amount", dataType: "slot", slot: "amount" },
+  { label: "鏀舵鏂瑰紡", prop: "receiptMethod", dataType: "slot", slot: "receiptMethod", width: "120" },
   { label: "澶囨敞", prop: "remark", showOverflowTooltip: true },
-  { label: "鎿嶄綔", prop: "operation", slot: "operation", width: "220", fixed: "right" },
+  { label: "鎿嶄綔", prop: "operation", dataType: "slot", slot: "operation", width: "200", fixed: "right" },
 ];
 
 const dataList = ref([]);
+const tableLoading = ref(false);
 const dialogVisible = ref(false);
 const dialogTitle = ref("");
 const formRef = ref(null);
 const isEdit = ref(false);
+const isView = ref(false);
 const currentId = ref(null);
+const submitLoading = ref(false);
 
-const customerList = [
-  { id: 1, name: "鍖椾含绉戞妧鏈夐檺鍏徃" },
-  { id: 2, name: "涓婃捣璐告槗鍏徃" },
-  { id: 3, name: "骞垮窞瀹炰笟鏈夐檺鍏徃" },
-  { id: 4, name: "娣卞湷鐢靛瓙鍏徃" },
-];
+const customerList = ref([]);
+const outboundBatchList = ref([]);
+const outboundBatchOptions = ref([]);
+const outboundBatchLoading = ref(false);
+const outboundSelectVisible = ref(false);
+const outboundTableRef = ref(null);
+const dialogOutboundSelection = ref([]);
 
-const outList = [
-  { outCode: "CK2024001", customerId: 1 },
-  { outCode: "CK2024002", customerId: 2 },
-  { outCode: "CK2024003", customerId: 3 },
-];
+const getReceiptMethodLabel = (value) => {
+  if (value === undefined || value === null || value === "") return "-";
+  const item = payment_methods.value?.find((m) => String(m.value) === String(value));
+  return item?.label ?? value;
+};
+
+const getDefaultReceiptMethod = () => payment_methods.value?.[0]?.value ?? "";
 
 const form = reactive({
   receiptCode: "",
   customerId: "",
   receiptDate: "",
   amount: 0,
-  receiptMethod: "bank_transfer",
-  bankAccount: "",
-  relatedDocs: [],
+  receiptMethod: "",
+  stockOutRecordIds: [],
+  outboundBatches: "",
   remark: "",
 });
 
 const rules = {
   customerId: [{ required: true, message: "璇烽�夋嫨瀹㈡埛", trigger: "change" }],
+  stockOutRecordIds: [{ required: true, type: "array", min: 1, message: "璇烽�夋嫨鍏宠仈鍗曟嵁", trigger: "change" }],
   receiptDate: [{ required: true, message: "璇烽�夋嫨鏀舵鏃ユ湡", trigger: "change" }],
   amount: [{ required: true, message: "璇疯緭鍏ユ敹娆鹃噾棰�", trigger: "blur" }],
   receiptMethod: [{ required: true, message: "璇烽�夋嫨鏀舵鏂瑰紡", trigger: "change" }],
 };
 
-const mockData = [
-  { id: 1, receiptCode: "SK2024001", customerId: 1, customerName: "鍖椾含绉戞妧鏈夐檺鍏徃", receiptDate: "2024-01-16", amount: 3000, receiptMethod: "bank_transfer", status: "confirmed", relatedDocs: ["CK2024001"], remark: "" },
-  { id: 2, receiptCode: "SK2024002", customerId: 2, customerName: "涓婃捣璐告槗鍏徃", receiptDate: "2024-01-18", amount: 5000, receiptMethod: "cash", status: "pending", relatedDocs: ["CK2024002"], remark: "" },
-  { id: 3, receiptCode: "SK2024003", customerId: 3, customerName: "骞垮窞瀹炰笟鏈夐檺鍏徃", receiptDate: "2024-01-20", amount: 8000, receiptMethod: "alipay", status: "confirmed", relatedDocs: ["CK2024003"], remark: "" },
-];
-
-const totalReceiptAmount = computed(() => {
-  return dataList.value.reduce((sum, item) => sum + Number(item.amount), 0);
-});
+const totalReceiptAmount = computed(() =>
+  dataList.value.reduce((sum, item) => sum + Number(item.amount || 0), 0)
+);
 
 const formatMoney = (value) => {
   if (value === undefined || value === null) return "0.00";
   return Number(value).toFixed(2).replace(/\B(?=(\d{3})+(?!\d))/g, ",");
 };
 
-const getReceiptMethodLabel = (method) => {
-  const map = {
-    bank_transfer: "閾惰杞处",
-    cash: "鐜伴噾",
-    check: "鏀エ",
-    draft: "姹囩エ",
-    alipay: "鏀粯瀹�",
-    wechat: "寰俊",
+const parseStockOutRecordIds = (value) => {
+  if (!value) return [];
+  if (Array.isArray(value)) return value;
+  return String(value)
+    .split(/[,锛宂/)
+    .map((s) => s.trim())
+    .filter(Boolean)
+    .map((s) => (/^\d+$/.test(s) ? Number(s) : s));
+};
+
+const formatOutboundBatches = (value) => {
+  if (value === undefined || value === null || value === "") return "";
+  if (Array.isArray(value)) return value.filter(Boolean).join("銆�");
+  return String(value)
+    .split(/[,锛宂/)
+    .map((s) => s.trim())
+    .filter(Boolean)
+    .join("銆�");
+};
+
+const normalizeTableRow = (row) => ({
+  ...row,
+  receiptCode: row.collectionNumber ?? row.receiptCode,
+  receiptDate: row.collectionDate ?? row.receiptDate,
+  amount: row.collectionAmount ?? row.amount,
+  receiptMethod: row.collectionMethod ?? row.receiptMethod ?? "",
+  stockOutRecordIds: row.stockOutRecordIds ?? row.stockOutRecordId ?? "",
+  outboundBatches: formatOutboundBatches(row.outboundBatches),
+});
+
+const getCustomerList = () => {
+  listCustomer({ current: -1, size: -1, type: 0 }).then((res) => {
+    if (res.code === 200) {
+      customerList.value = res.data?.records || [];
+    }
+  });
+};
+
+const normalizeOutboundBatchOptions = (data) => {
+  const list = Array.isArray(data) ? data : [];
+  return list.map((item, index) => {
+    if (typeof item === "string" || typeof item === "number") {
+      const text = String(item);
+      return { label: text, value: text, outboundAmount: 0 };
+    }
+    const label =
+      item.outboundBatches ??
+      item.batchNo ??
+      item.shippingNo ??
+      item.outboundNo ??
+      item.label ??
+      `鍑哄簱鍗�${index + 1}`;
+    const value = item.id ?? item.stockOutRecordId ?? label;
+    return { label: String(label), value, outboundAmount: Number(item.outboundAmount) || 0 };
+  });
+};
+
+const isSameOutboundId = (a, b) => String(a) === String(b);
+
+const getOutboundRowId = (row) => row?.id ?? row?.stockOutRecordId;
+
+const outboundBatchDisplayText = computed(() => {
+  if (isEdit.value || isView.value) {
+    return form.outboundBatches || "";
+  }
+  if (form.outboundBatches) return form.outboundBatches;
+  const ids = form.stockOutRecordIds || [];
+  if (!ids.length) return "";
+  const labels = outboundBatchOptions.value
+    .filter((opt) => ids.some((id) => isSameOutboundId(id, opt.value)))
+    .map((opt) => opt.label);
+  if (labels.length) return labels.join("銆�");
+  return ids.join("銆�");
+});
+
+const handleOutboundInputClick = () => {
+  if (isEdit.value || isView.value) return;
+  openOutboundSelectDialog();
+};
+
+/** 涓哄凡閫� ID 琛ュ叏閫夐」锛堢紪杈�/鏌ョ湅鍥炴樉锛� */
+const ensureOutboundOptionsForSelected = () => {
+  const ids = form.stockOutRecordIds || [];
+  ids.forEach((id) => {
+    const exists = outboundBatchOptions.value.some((opt) => isSameOutboundId(opt.value, id));
+    if (exists) return;
+    const fromList = outboundBatchList.value.find((row) => isSameOutboundId(getOutboundRowId(row), id));
+    if (fromList) {
+      const [option] = normalizeOutboundBatchOptions([fromList]);
+      if (option) outboundBatchOptions.value.push(option);
+      return;
+    }
+    outboundBatchOptions.value.push({
+      label: String(id),
+      value: id,
+      outboundAmount: 0,
+    });
+  });
+};
+
+const syncCollectionAmount = () => {
+  const selected = form.stockOutRecordIds || [];
+  const sum = outboundBatchOptions.value
+    .filter((opt) => selected.some((id) => isSameOutboundId(id, opt.value)))
+    .reduce((acc, opt) => acc + (Number(opt.outboundAmount) || 0), 0);
+  form.amount = sum > 0 ? Number(sum.toFixed(2)) : 0;
+};
+
+const restoreOutboundTableSelection = () => {
+  nextTick(() => {
+    const table = outboundTableRef.value;
+    if (!table) return;
+    table.clearSelection();
+    const selectedIds = new Set((form.stockOutRecordIds || []).map((id) => String(id)));
+    outboundBatchList.value.forEach((row) => {
+      const rowId = getOutboundRowId(row);
+      if (rowId !== undefined && rowId !== null && selectedIds.has(String(rowId))) {
+        table.toggleRowSelection(row, true);
+      }
+    });
+  });
+};
+
+const loadOutboundBatches = (customerId, keepSelected = false) => {
+  if (!customerId) {
+    outboundBatchList.value = [];
+    outboundBatchOptions.value = [];
+    if (!keepSelected) {
+      form.stockOutRecordIds = [];
+      form.amount = 0;
+    }
+    return Promise.resolve();
+  }
+  outboundBatchLoading.value = true;
+  return getOutboundBatchesByCustomer({ customerId })
+    .then((res) => {
+      if (res.code === 200) {
+        const list = res.data?.records ?? res.data ?? [];
+        outboundBatchList.value = Array.isArray(list) ? list : [];
+        outboundBatchOptions.value = normalizeOutboundBatchOptions(list);
+      } else {
+        outboundBatchList.value = [];
+        outboundBatchOptions.value = [];
+      }
+    })
+    .catch(() => {
+      outboundBatchList.value = [];
+      outboundBatchOptions.value = [];
+    })
+    .finally(() => {
+      outboundBatchLoading.value = false;
+      if (keepSelected) {
+        ensureOutboundOptionsForSelected();
+        restoreOutboundTableSelection();
+      }
+    });
+};
+
+const handleCustomerChange = (customerId) => {
+  form.stockOutRecordIds = [];
+  form.outboundBatches = "";
+  form.amount = 0;
+  loadOutboundBatches(customerId);
+};
+
+const openOutboundSelectDialog = () => {
+  if (!form.customerId || isEdit.value || isView.value) return;
+  outboundSelectVisible.value = true;
+  loadOutboundBatches(form.customerId, true).then(() => {
+    restoreOutboundTableSelection();
+  });
+};
+
+const handleOutboundDialogSelectionChange = (selection) => {
+  dialogOutboundSelection.value = selection;
+};
+
+const confirmOutboundSelection = () => {
+  if (dialogOutboundSelection.value.length === 0) {
+    ElMessage.warning("璇疯嚦灏戦�夋嫨涓�鏉″叧鑱斿崟鎹�");
+    return;
+  }
+  form.stockOutRecordIds = dialogOutboundSelection.value
+    .map((row) => getOutboundRowId(row))
+    .filter((id) => id !== undefined && id !== null);
+  form.outboundBatches = dialogOutboundSelection.value
+    .map((row) => row.outboundBatches ?? row.batchNo ?? row.shippingNo ?? "")
+    .filter(Boolean)
+    .join("銆�");
+  outboundSelectVisible.value = false;
+  syncCollectionAmount();
+  formRef.value?.validateField("stockOutRecordIds");
+};
+
+const handleOutboundDialogClosed = () => {
+  dialogOutboundSelection.value = [];
+};
+
+const appendFilterParams = (params) => {
+  if (filters.collectionNumber) {
+    params.collectionNumber = filters.collectionNumber;
+  }
+  if (filters.customerId) {
+    params.customerId = filters.customerId;
+  }
+  if (filters.collectionMethod) {
+    params.collectionMethod = filters.collectionMethod;
+  }
+  if (filters.dateRange?.length === 2) {
+    params.startDate = filters.dateRange[0];
+    params.endDate = filters.dateRange[1];
+  }
+  return params;
+};
+
+const buildListParams = () =>
+  appendFilterParams({
+    current: pagination.currentPage,
+    size: pagination.pageSize,
+  });
+
+const buildExportParams = () => appendFilterParams({});
+
+const buildSubmitPayload = (forUpdate = false) => {
+  const payload = {
+    customerId: form.customerId,
+    collectionDate: form.receiptDate,
+    collectionAmount: form.amount,
+    collectionMethod: form.receiptMethod,
+    collectionNumber: form.receiptCode || "",
+    remark: form.remark || "",
+    stockOutRecordIds: (form.stockOutRecordIds || []).join(","),
   };
-  return map[method] || method;
+  if (forUpdate) {
+    payload.id = currentId.value;
+  }
+  return payload;
+};
+
+const fillFormFromRow = (row) => {
+  const stockOutRecordIds = parseStockOutRecordIds(row.stockOutRecordIds ?? row.stockOutRecordId);
+  Object.assign(form, {
+    receiptCode: row.receiptCode ?? row.collectionNumber ?? "",
+    customerId: row.customerId,
+    receiptDate: row.receiptDate ?? row.collectionDate ?? "",
+    amount: Number(row.amount ?? row.collectionAmount ?? 0),
+    receiptMethod: row.receiptMethod ?? row.collectionMethod ?? "",
+    stockOutRecordIds,
+    outboundBatches: formatOutboundBatches(row.outboundBatches),
+    remark: row.remark ?? "",
+  });
+};
+
+const closeDialog = () => {
+  dialogVisible.value = false;
+  outboundSelectVisible.value = false;
+  isView.value = false;
+  isEdit.value = false;
+};
+
+const handleExport = () => {
+  const params = buildExportParams();
+  proxy.download("/accountSalesCollection/exportAccountSalesCollection", params, `鏀舵鍗昣${Date.now()}.xlsx`);
 };
 
 const getTableData = () => {
-  let result = [...mockData];
-  if (filters.receiptCode) {
-    result = result.filter(item => item.receiptCode.includes(filters.receiptCode));
-  }
-  if (filters.customerId) {
-    result = result.filter(item => item.customerId === filters.customerId);
-  }
-  if (filters.receiptMethod) {
-    result = result.filter(item => item.receiptMethod === filters.receiptMethod);
-  }
-  pagination.total = result.length;
-  dataList.value = result.slice((pagination.currentPage - 1) * pagination.pageSize, pagination.currentPage * pagination.pageSize);
+  tableLoading.value = true;
+  listPageAccountSalesCollection(buildListParams())
+    .then((res) => {
+      const ok = res.code === 200 || res.code === 0;
+      if (ok && res.data) {
+        pagination.total = res.data.total ?? 0;
+        dataList.value = (res.data.records ?? []).map(normalizeTableRow);
+      } else {
+        ElMessage.error(res.msg || "鏌ヨ澶辫触");
+        dataList.value = [];
+        pagination.total = 0;
+      }
+    })
+    .catch(() => {
+      dataList.value = [];
+      pagination.total = 0;
+      ElMessage.error("鏌ヨ澶辫触");
+    })
+    .finally(() => {
+      tableLoading.value = false;
+    });
+};
+
+const onSearch = () => {
+  pagination.currentPage = 1;
+  getTableData();
 };
 
 const resetFilters = () => {
-  filters.receiptCode = "";
+  filters.collectionNumber = "";
   filters.customerId = "";
-  filters.receiptMethod = "";
+  filters.collectionMethod = "";
+  filters.dateRange = [];
   pagination.currentPage = 1;
   getTableData();
 };
@@ -255,88 +632,89 @@
 
 const add = () => {
   isEdit.value = false;
+  isView.value = false;
   dialogTitle.value = "鏂板鏀舵";
   Object.assign(form, {
     receiptCode: "SK" + Date.now().toString().slice(-8),
     customerId: "",
-    receiptDate: new Date().toISOString().split('T')[0],
+    receiptDate: new Date().toISOString().split("T")[0],
     amount: 0,
-    receiptMethod: "bank_transfer",
-    bankAccount: "",
-    relatedDocs: [],
+    receiptMethod: getDefaultReceiptMethod(),
+    stockOutRecordIds: [],
+    outboundBatches: "",
     remark: "",
   });
+  outboundBatchList.value = [];
+  outboundBatchOptions.value = [];
   dialogVisible.value = true;
 };
 
 const edit = (row) => {
   isEdit.value = true;
+  isView.value = false;
   currentId.value = row.id;
   dialogTitle.value = "缂栬緫鏀舵";
-  Object.assign(form, row);
+  fillFormFromRow(row);
   dialogVisible.value = true;
 };
 
 const view = (row) => {
-  ElMessage.info(`鏌ョ湅鏀舵鍗�: ${row.receiptCode}`);
-};
-
-const handleConfirm = (row) => {
-  ElMessageBox.confirm("纭璇ユ敹娆惧崟鍚楋紵", "鎻愮ず", {
-    confirmButtonText: "纭",
-    cancelButtonText: "鍙栨秷",
-    type: "info",
-  }).then(() => {
-    const index = mockData.findIndex(item => item.id === row.id);
-    if (index !== -1) {
-      mockData[index].status = "confirmed";
-    }
-    ElMessage.success("纭鎴愬姛");
-    getTableData();
-  });
+  isView.value = true;
+  isEdit.value = false;
+  dialogTitle.value = "鏌ョ湅鏀舵";
+  fillFormFromRow(row);
+  dialogVisible.value = true;
 };
 
 const handleDelete = (row) => {
-  ElMessageBox.confirm("纭鍒犻櫎璇ユ敹娆惧崟鍚楋紵", "鎻愮ず", {
+  ElMessageBox.confirm(`纭鍒犻櫎鏀舵鍗曘��${row.receiptCode ?? row.collectionNumber}銆嶅悧锛焋, "鎻愮ず", {
     confirmButtonText: "纭畾",
     cancelButtonText: "鍙栨秷",
     type: "warning",
   }).then(() => {
-    const index = mockData.findIndex(item => item.id === row.id);
-    if (index !== -1) {
-      mockData.splice(index, 1);
-    }
-    ElMessage.success("鍒犻櫎鎴愬姛");
-    getTableData();
+    deleteAccountSalesCollection([row.id])
+      .then((res) => {
+        if (res.code === 200) {
+          ElMessage.success("鍒犻櫎鎴愬姛");
+          getTableData();
+        } else {
+          ElMessage.error(res.msg || "鍒犻櫎澶辫触");
+        }
+      })
+      .catch(() => {
+        ElMessage.error("鍒犻櫎澶辫触");
+      });
   });
-};
-
-const handleOut = () => {
-  ElMessage.success("瀵煎嚭鎴愬姛");
 };
 
 const submitForm = () => {
   formRef.value.validate((valid) => {
-    if (valid) {
-      const customer = customerList.find(item => item.id === form.customerId);
-      if (isEdit.value) {
-        const index = mockData.findIndex(item => item.id === currentId.value);
-        if (index !== -1) {
-          mockData[index] = { ...mockData[index], ...form, customerName: customer?.name };
+    if (!valid) return;
+    submitLoading.value = true;
+    const request = isEdit.value
+      ? updateAccountSalesCollection(buildSubmitPayload(true))
+      : addAccountSalesCollection(buildSubmitPayload());
+    request
+      .then((res) => {
+        if (res.code === 200) {
+          ElMessage.success(isEdit.value ? "淇敼鎴愬姛" : "鏂板鎴愬姛");
+          closeDialog();
+          getTableData();
+        } else {
+          ElMessage.error(res.msg || (isEdit.value ? "淇敼澶辫触" : "鏂板澶辫触"));
         }
-        ElMessage.success("缂栬緫鎴愬姛");
-      } else {
-        const newId = mockData.length > 0 ? Math.max(...mockData.map(item => item.id)) + 1 : 1;
-        mockData.push({ id: newId, ...form, customerName: customer?.name, status: "pending" });
-        ElMessage.success("鏂板鎴愬姛");
-      }
-      dialogVisible.value = false;
-      getTableData();
-    }
+      })
+      .catch(() => {
+        ElMessage.error(isEdit.value ? "淇敼澶辫触" : "鏂板澶辫触");
+      })
+      .finally(() => {
+        submitLoading.value = false;
+      });
   });
 };
 
 onMounted(() => {
+  getCustomerList();
   getTableData();
 });
 </script>
@@ -353,4 +731,10 @@
   color: #67c23a;
   font-weight: bold;
 }
+
+.outbound-batch-input:not(.is-disabled) {
+  :deep(.el-input__wrapper) {
+    cursor: pointer;
+  }
+}
 </style>
diff --git a/src/views/financialManagement/receivable/reconciliation.vue b/src/views/financialManagement/receivable/reconciliation.vue
index 883e12e..b1bff0e 100644
--- a/src/views/financialManagement/receivable/reconciliation.vue
+++ b/src/views/financialManagement/receivable/reconciliation.vue
@@ -2,8 +2,8 @@
   <div class="app-container">
     <el-form :model="filters" :inline="true">
       <el-form-item label="瀹㈡埛:">
-        <el-select v-model="filters.customerId" placeholder="璇烽�夋嫨瀹㈡埛" clearable style="width: 200px;">
-          <el-option v-for="item in customerList" :key="item.id" :label="item.name" :value="item.id" />
+        <el-select v-model="filters.customerId" placeholder="璇烽�夋嫨瀹㈡埛" clearable filterable style="width: 200px;">
+          <el-option v-for="item in customerList" :key="item.id" :label="item.customerName" :value="item.id" />
         </el-select>
       </el-form-item>
       <el-form-item label="瀵硅处鏈熼棿:">
@@ -29,6 +29,7 @@
         rowKey="id"
         :column="columns"
         :tableData="dataList"
+        :tableLoading="tableLoading"
         :page="{
           current: pagination.currentPage,
           size: pagination.pageSize,
@@ -36,21 +37,22 @@
         }"
         @pagination="changePage"
       >
-        <template #beginBalance="{ row }">
-          <span :class="row.beginBalance >= 0 ? 'text-success' : 'text-danger'">楼{{ formatMoney(row.beginBalance) }}</span>
+        <template #openingBalance="{ row }">
+          <span :class="row.openingBalance >= 0 ? 'text-success' : 'text-danger'">楼{{ formatMoney(row.openingBalance) }}</span>
         </template>
-        <template #currentReceivable="{ row }">
-          <span class="text-primary">楼{{ formatMoney(row.currentReceivable) }}</span>
+        <template #currentPlan="{ row }">
+          <span class="text-primary">楼{{ formatMoney(row.currentPlan) }}</span>
         </template>
-        <template #currentReceipt="{ row }">
-          <span class="text-success">楼{{ formatMoney(row.currentReceipt) }}</span>
+        <template #currentActually="{ row }">
+          <span class="text-success">楼{{ formatMoney(row.currentActually) }}</span>
         </template>
-        <template #endBalance="{ row }">
-          <span :class="row.endBalance >= 0 ? 'text-success' : 'text-danger'">楼{{ formatMoney(row.endBalance) }}</span>
+        <template #closingBalance="{ row }">
+          <span :class="row.closingBalance >= 0 ? 'text-success' : 'text-danger'">楼{{ formatMoney(row.closingBalance) }}</span>
         </template>
         <template #operation="{ row }">
           <el-button type="primary" link @click="viewDetail(row)">鏌ョ湅鏄庣粏</el-button>
-          <el-button type="primary" link @click="printStatement(row)">鎵撳嵃</el-button>
+          <!-- <el-button type="primary" link @click="printStatement(row)">鎵撳嵃</el-button> -->
+          <el-button type="danger" link @click="handleDelete(row)">鍒犻櫎</el-button>
         </template>
       </PIMTable>
     </div>
@@ -60,7 +62,7 @@
         <h3>{{ currentCustomer }} 搴旀敹瀵硅处鍗�</h3>
         <p>瀵硅处鏈熼棿: {{ currentPeriod }}</p>
       </div>
-      <el-table :data="detailData" border style="width: 100%">
+      <el-table :data="detailData" border style="width: 100%" v-loading="detailLoading">
         <el-table-column prop="date" label="鏃ユ湡" width="120" />
         <el-table-column prop="type" label="绫诲瀷" width="100">
           <template #default="{ row }">
@@ -98,52 +100,68 @@
         <el-row :gutter="20">
           <el-col :span="12">
             <el-form-item label="閫夋嫨瀹㈡埛" prop="customerId">
-              <el-select v-model="generateForm.customerId" placeholder="璇烽�夋嫨瀹㈡埛" style="width: 100%;" @change="onCustomerChange">
-                <el-option v-for="item in customerList" :key="item.id" :label="item.name" :value="item.id" />
+              <el-select
+                v-model="generateForm.customerId"
+                placeholder="璇烽�夋嫨瀹㈡埛"
+                style="width: 100%;"
+                filterable
+                @change="onCustomerChange"
+              >
+                <el-option v-for="item in customerList" :key="item.id" :label="item.customerName" :value="item.id" />
               </el-select>
             </el-form-item>
           </el-col>
           <el-col :span="12">
-            <el-form-item label="瀵硅处鏈堜唤" prop="period">
-              <el-date-picker v-model="generateForm.period" type="month" placeholder="閫夋嫨鏈堜唤" value-format="YYYY-MM" style="width: 100%;" @change="onPeriodChange" />
+            <el-form-item label="瀵硅处鏈堜唤" prop="statementMonth">
+              <el-date-picker v-model="generateForm.statementMonth" type="month" placeholder="閫夋嫨鏈堜唤" value-format="YYYY-MM" style="width: 100%;" @change="onStatementMonthChange" />
             </el-form-item>
           </el-col>
         </el-row>
       </el-form>
 
-      <div v-if="salesData.length > 0" class="sales-section">
-        <div class="section-title">鏈湀閿�鍞暟鎹�</div>
-        <el-table :data="salesData" border style="width: 100%; margin-bottom: 15px;" v-loading="salesLoading" @selection-change="handleSalesSelectionChange">
+      <div v-if="statementDetailLoaded" class="sales-section">
+        <div v-if="salesData.length > 0" class="section-title">鏈湀閿�鍞暟鎹�</div>
+        <el-table
+          v-if="salesData.length > 0"
+          ref="salesTableRef"
+          :data="salesData"
+          border
+          row-key="id"
+          style="width: 100%; margin-bottom: 15px;"
+          v-loading="salesLoading"
+          @selection-change="handleSalesSelectionChange"
+        >
           <el-table-column type="selection" width="55" align="center" />
-          <el-table-column prop="date" label="鏃ユ湡" width="120" />
-          <el-table-column prop="code" label="鍗曟嵁缂栧彿" width="150" />
+          <el-table-column prop="occurrenceDate" label="鏃ユ湡" width="120" />
+          <el-table-column prop="receiptNumber" label="鍗曟嵁缂栧彿" width="150" />
           <el-table-column prop="type" label="绫诲瀷" width="100">
             <template #default="{ row }">
-              <el-tag :type="row.type === '鍑哄簱' ? 'success' : row.type === '鏀舵' ? 'primary' : 'danger'">{{ row.type }}</el-tag>
+              <el-tag :type="getDetailTypeTagType(row.type)">{{ row.typeLabel }}</el-tag>
             </template>
           </el-table-column>
           <el-table-column prop="amount" label="閲戦" width="120">
             <template #default="{ row }">
-              <span :class="row.type === '鍑哄簱' ? 'text-primary' : row.type === '鏀舵' ? 'text-success' : 'text-danger'">楼{{ formatMoney(row.amount) }}</span>
+              <span :class="getDetailAmountClass(row.type)">楼{{ formatMoney(row.amount) }}</span>
             </template>
           </el-table-column>
           <el-table-column prop="remark" label="澶囨敞" />
         </el-table>
+        <el-empty v-else description="璇ュ鎴锋湰鏈堟殏鏃犳槑缁嗘暟鎹�" :image-size="80" />
 
         <div class="summary-row">
-          <span>鏈熷垵浣欓: <strong class="text-primary">楼{{ formatMoney(generateForm.beginBalance) }}</strong></span>
-          <span>鏈湡搴旀敹: <strong class="text-primary">楼{{ formatMoney(generateForm.currentReceivable) }}</strong></span>
-          <span>鏈湡鏀舵: <strong class="text-success">楼{{ formatMoney(generateForm.currentReceipt) }}</strong></span>
-          <span>鏈熸湯浣欓: <strong :class="calculateEndBalance(generateForm.beginBalance, generateForm.currentReceivable, generateForm.currentReceipt) >= 0 ? 'text-success' : 'text-danger'">楼{{ formatMoney(calculateEndBalance(generateForm.beginBalance, generateForm.currentReceivable, generateForm.currentReceipt)) }}</strong></span>
+          <span>鏈熷垵浣欓: <strong class="text-primary">楼{{ formatMoney(generateForm.openingBalance) }}</strong></span>
+          <span>鏈湡搴旀敹: <strong class="text-primary">楼{{ formatMoney(generateForm.currentPlan) }}</strong></span>
+          <span>鏈湡鏀舵: <strong class="text-success">楼{{ formatMoney(generateForm.currentActually) }}</strong></span>
+          <span>鏈熸湯浣欓: <strong :class="displayClosingBalance >= 0 ? 'text-success' : 'text-danger'">楼{{ formatMoney(displayClosingBalance) }}</strong></span>
         </div>
       </div>
 
-      <div v-else-if="generateForm.customerId && !salesLoading" class="empty-tip">
+      <div v-else-if="generateForm.customerId && generateForm.statementMonth && !salesLoading" class="empty-tip">
         <el-empty description="璇ュ鎴锋湰鏈堟殏鏃犻攢鍞暟鎹�" />
       </div>
 
       <template #footer>
-        <el-button type="primary" @click="confirmGenerate" :disabled="!canGenerate">纭鐢熸垚</el-button>
+        <el-button type="primary" @click="confirmGenerate" :disabled="!canGenerate" :loading="submitLoading">纭鐢熸垚</el-button>
         <el-button @click="generateDialogVisible = false">鍙栨秷</el-button>
       </template>
     </FormDialog>
@@ -151,9 +169,20 @@
 </template>
 
 <script setup>
-import { ref, reactive, onMounted, computed } from "vue";
-import { ElMessage } from "element-plus";
+import { ref, reactive, onMounted, computed, nextTick, getCurrentInstance } from "vue";
+import { ElMessage, ElMessageBox } from "element-plus";
 import FormDialog from "@/components/Dialog/FormDialog.vue";
+import { listCustomer } from "@/api/basicData/customer.js";
+import {
+  getAccountStatementDetailsByMonth,
+  addAccountStatement,
+  listPageAccountStatement,
+  deleteAccountStatement,
+} from "@/api/financialManagement/accountStatement.js";
+
+const ACCOUNT_TYPE_RECEIVABLE = 1;
+
+const { proxy } = getCurrentInstance();
 
 defineOptions({
   name: "搴旀敹瀵硅处",
@@ -172,56 +201,192 @@
 });
 
 const columns = [
-  { label: "瀵硅处鍗曞彿", prop: "statementCode", width: "150" },
+  { label: "瀵硅处鍗曞彿", prop: "statementNumber", width: "150" },
   { label: "瀹㈡埛鍚嶇О", prop: "customerName", width: "180" },
-  { label: "瀵硅处鏈熼棿", prop: "period", width: "150" },
-  { label: "鏈熷垵浣欓", prop: "beginBalance", slot: "beginBalance" },
-  { label: "鏈湡搴旀敹", prop: "currentReceivable", slot: "currentReceivable" },
-  { label: "鏈湡鏀舵", prop: "currentReceipt", slot: "currentReceipt" },
-  { label: "鏈熸湯浣欓", prop: "endBalance", slot: "endBalance" },
-  { label: "鎿嶄綔", prop: "operation", slot: "operation", width: "150", fixed: "right" },
+  { label: "瀵硅处鏈熼棿", prop: "statementMonth", width: "150" },
+  { label: "鏈熷垵浣欓", prop: "openingBalance", dataType: "slot", slot: "openingBalance" },
+  { label: "鏈湡搴旀敹", prop: "currentPlan", dataType: "slot", slot: "currentPlan" },
+  { label: "鏈湡鏀舵", prop: "currentActually", dataType: "slot", slot: "currentActually" },
+  { label: "鏈熸湯浣欓", prop: "closingBalance", dataType: "slot", slot: "closingBalance" },
+  { label: "鎿嶄綔", prop: "operation", dataType: "slot", slot: "operation", width: "200", fixed: "right" },
 ];
 
 const dataList = ref([]);
+const tableLoading = ref(false);
+const submitLoading = ref(false);
 const detailDialogVisible = ref(false);
 const currentCustomer = ref("");
 const currentPeriod = ref("");
 const detailData = ref([]);
+const detailLoading = ref(false);
 
 const generateDialogVisible = ref(false);
 const salesLoading = ref(false);
+const statementDetailLoaded = ref(false);
 const salesData = ref([]);
 const selectedSales = ref([]);
+const salesTableRef = ref(null);
+const customerList = ref([]);
+
+/** 鏄庣粏 type锛�1鍑哄簱 2鍏ュ簱 3鏀舵 4浠樻 5閫�璐� */
+const STATEMENT_DETAIL_TYPE_MAP = {
+  1: "鍑哄簱",
+  2: "鍏ュ簱",
+  3: "鏀舵",
+  4: "浠樻",
+  5: "閫�璐�",
+};
+
+const calculateEndBalance = (openingBalance, currentPlan, currentActually) => {
+  return openingBalance + currentPlan - currentActually;
+};
+
+const getDetailTypeLabel = (type) => STATEMENT_DETAIL_TYPE_MAP[Number(type)] ?? "";
+
+const getDetailTypeTagType = (type) => {
+  const t = Number(type);
+  if (t === 1) return "success";
+  if (t === 3) return "primary";
+  if (t === 5) return "danger";
+  return "info";
+};
+
+const getDetailAmountClass = (type) => {
+  const t = Number(type);
+  if (t === 1) return "text-primary";
+  if (t === 3) return "text-success";
+  return "text-danger";
+};
 
 const generateForm = reactive({
   customerId: "",
   customerName: "",
-  period: "",
-  beginBalance: 0,
-  currentReceivable: 0,
-  currentReceipt: 0,
+  statementMonth: "",
+  openingBalance: 0,
+  currentPlan: 0,
+  currentActually: 0,
+  closingBalance: 0,
+});
+
+const displayClosingBalance = computed(() => {
+  return calculateEndBalance(
+    generateForm.openingBalance,
+    generateForm.currentPlan,
+    generateForm.currentActually
+  );
 });
 
 const canGenerate = computed(() => {
-  return generateForm.customerId && generateForm.period && selectedSales.value.length > 0;
+  return generateForm.customerId && generateForm.statementMonth && selectedSales.value.length > 0;
 });
 
-const customerList = [
-  { id: 1, name: "鍖椾含绉戞妧鏈夐檺鍏徃" },
-  { id: 2, name: "涓婃捣璐告槗鍏徃" },
-  { id: 3, name: "骞垮窞瀹炰笟鏈夐檺鍏徃" },
-  { id: 4, name: "娣卞湷鐢靛瓙鍏徃" },
-];
-
-const mockData = [
-  { id: 1, statementCode: "DZ202401001", customerId: 1, customerName: "鍖椾含绉戞妧鏈夐檺鍏徃", period: "2024-01", beginBalance: 10000, currentReceivable: 15000, currentReceipt: 8000, endBalance: 17000 },
-  { id: 2, statementCode: "DZ202401002", customerId: 2, customerName: "涓婃捣璐告槗鍏徃", period: "2024-01", beginBalance: 5000, currentReceivable: 12000, currentReceipt: 10000, endBalance: 7000 },
-  { id: 3, statementCode: "DZ202402001", customerId: 1, customerName: "鍖椾含绉戞妧鏈夐檺鍏徃", period: "2024-02", beginBalance: 17000, currentReceivable: 20000, currentReceipt: 15000, endBalance: 22000 },
-];
-
-const calculateEndBalance = (beginBalance, currentReceivable, currentReceipt) => {
-  return beginBalance + currentReceivable - currentReceipt;
+const applyStatementSummary = (data) => {
+  generateForm.openingBalance = Number(data.openingBalance ?? 0);
+  generateForm.currentPlan = Number(data.currentPlan ?? 0);
+  generateForm.currentActually = Number(data.currentActually ?? 0);
+  generateForm.closingBalance = Number(
+    data.closingBalance ??
+      calculateEndBalance(
+        generateForm.openingBalance,
+        generateForm.currentPlan,
+        generateForm.currentActually
+      )
+  );
 };
+
+const getCustomerList = () => {
+  listCustomer({ current: -1, size: -1, type: 0 }).then((res) => {
+    if (res.code === 200) {
+      customerList.value = res.data?.records || [];
+    }
+  });
+};
+
+const normalizeSalesRows = (list) => {
+  const rows = Array.isArray(list) ? list : [];
+  return rows.map((item, index) => {
+    const type = Number(item.type);
+    return {
+      id: item.id ?? `detail-${index}`,
+      accountStatementId: item.accountStatementId,
+      occurrenceDate: item.occurrenceDate ?? "",
+      receiptNumber: item.receiptNumber ?? "",
+      type,
+      typeLabel: getDetailTypeLabel(type),
+      amount: Math.abs(Number(item.amount ?? 0)),
+      remark: item.remark ?? "",
+    };
+  });
+};
+
+const selectAllSalesRows = (keepApiSummary = false) => {
+  nextTick(() => {
+    const table = salesTableRef.value;
+    if (!table) return;
+    table.clearSelection();
+    salesData.value.forEach((row) => table.toggleRowSelection(row, true));
+    selectedSales.value = [...salesData.value];
+    if (!keepApiSummary) {
+      calculateSummary();
+    }
+  });
+};
+
+const isNumericId = (id) => id !== undefined && id !== null && id !== "" && /^\d+$/.test(String(id));
+
+const buildFilterParams = (params = {}) => {
+  const result = { ...params, accountType: ACCOUNT_TYPE_RECEIVABLE };
+  if (filters.customerId) {
+    result.customerId = filters.customerId;
+  }
+  if (filters.startMonth && filters.endMonth && filters.startMonth === filters.endMonth) {
+    result.statementMonth = filters.startMonth;
+  } else if (filters.startMonth) {
+    result.startMonth = filters.startMonth;
+  }
+  if (filters.endMonth && filters.startMonth !== filters.endMonth) {
+    result.endMonth = filters.endMonth;
+  }
+  return result;
+};
+
+const buildListParams = () =>
+  buildFilterParams({
+    current: pagination.currentPage,
+    size: pagination.pageSize,
+  });
+
+const buildExportParams = () => buildFilterParams({});
+
+const buildDetailSubmitItem = (row) => {
+  const item = {
+    occurrenceDate: row.occurrenceDate,
+    receiptNumber: row.receiptNumber,
+    type: row.type,
+    amount: row.amount,
+    remark: row.remark ?? "",
+  };
+  if (isNumericId(row.id)) {
+    item.id = Number(row.id);
+  }
+  if (row.accountStatementId) {
+    item.accountStatementId = row.accountStatementId;
+  }
+  return item;
+};
+
+const buildAddPayload = () => ({
+  customerId: generateForm.customerId,
+  customerName: generateForm.customerName,
+  statementMonth: generateForm.statementMonth,
+  accountType: ACCOUNT_TYPE_RECEIVABLE,
+  statementNumber: "",
+  openingBalance: generateForm.openingBalance,
+  currentPlan: generateForm.currentPlan,
+  currentActually: generateForm.currentActually,
+  closingBalance: generateForm.closingBalance,
+  accountStatementDetails: selectedSales.value.map(buildDetailSubmitItem),
+});
 
 const formatMoney = (value) => {
   if (value === undefined || value === null) return "0.00";
@@ -229,15 +394,27 @@
 };
 
 const getTableData = () => {
-  let result = [...mockData];
-  if (filters.customerId) {
-    result = result.filter(item => item.customerId === filters.customerId);
-  }
-  if (filters.startMonth && filters.endMonth) {
-    result = result.filter(item => item.period >= filters.startMonth && item.period <= filters.endMonth);
-  }
-  pagination.total = result.length;
-  dataList.value = result.slice((pagination.currentPage - 1) * pagination.pageSize, pagination.currentPage * pagination.pageSize);
+  tableLoading.value = true;
+  listPageAccountStatement(buildListParams())
+    .then((res) => {
+      const ok = res.code === 200 || res.code === 0;
+      if (ok && res.data) {
+        pagination.total = res.data.total ?? 0;
+        dataList.value = res.data.records ?? [];
+      } else {
+        ElMessage.error(res.msg || "鏌ヨ澶辫触");
+        dataList.value = [];
+        pagination.total = 0;
+      }
+    })
+    .catch(() => {
+      dataList.value = [];
+      pagination.total = 0;
+      ElMessage.error("鏌ヨ澶辫触");
+    })
+    .finally(() => {
+      tableLoading.value = false;
+    });
 };
 
 const resetFilters = () => {
@@ -257,83 +434,97 @@
 const generateStatement = () => {
   generateForm.customerId = "";
   generateForm.customerName = "";
-  generateForm.period = "";
-  generateForm.beginBalance = 0;
-  generateForm.currentReceivable = 0;
-  generateForm.currentReceipt = 0;
+  generateForm.statementMonth = "";
+  generateForm.openingBalance = 0;
+  generateForm.currentPlan = 0;
+  generateForm.currentActually = 0;
+  generateForm.closingBalance = 0;
+  statementDetailLoaded.value = false;
   salesData.value = [];
   selectedSales.value = [];
   generateDialogVisible.value = true;
 };
 
 const onCustomerChange = (customerId) => {
-  const customer = customerList.find(item => item.id === customerId);
-  if (customer) {
-    generateForm.customerName = customer.name;
-  }
+  const customer = customerList.value.find((item) => item.id === customerId);
+  generateForm.customerName = customer?.customerName ?? "";
   loadSalesData();
 };
 
-const onPeriodChange = () => {
+const onStatementMonthChange = () => {
   loadSalesData();
 };
 
 const loadSalesData = () => {
-  if (!generateForm.customerId || !generateForm.period) {
+  if (!generateForm.customerId || !generateForm.statementMonth) {
     salesData.value = [];
+    selectedSales.value = [];
+    statementDetailLoaded.value = false;
+    generateForm.openingBalance = 0;
+    generateForm.currentPlan = 0;
+    generateForm.currentActually = 0;
+    generateForm.closingBalance = 0;
     return;
   }
 
   salesLoading.value = true;
+  selectedSales.value = [];
+  statementDetailLoaded.value = false;
 
-  setTimeout(() => {
-    const mockSalesData = [
-      { id: 1, date: generateForm.period + "-03", code: "CK2024001", type: "鍑哄簱", amount: 8000, remark: "浜у搧A閿�鍞�" },
-      { id: 2, date: generateForm.period + "-08", code: "SK2024001", type: "鏀舵", amount: 5000, remark: "瀹㈡埛鍥炴" },
-      { id: 3, date: generateForm.period + "-12", code: "CK2024002", type: "鍑哄簱", amount: 12000, remark: "浜у搧B閿�鍞�" },
-      { id: 4, date: generateForm.period + "-15", code: "TH2024001", type: "閫�璐�", amount: 2000, remark: "璐ㄩ噺闂閫�璐�" },
-      { id: 5, date: generateForm.period + "-20", code: "CK2024003", type: "鍑哄簱", amount: 5000, remark: "浜у搧C閿�鍞�" },
-      { id: 6, date: generateForm.period + "-25", code: "SK2024002", type: "鏀舵", amount: 8000, remark: "瀹㈡埛鍥炴" },
-    ];
+  getAccountStatementDetailsByMonth({
+    accountType: ACCOUNT_TYPE_RECEIVABLE,
+    customerId: generateForm.customerId,
+    statementMonth: generateForm.statementMonth,
+  })
+    .then((res) => {
+      if (res.code === 200) {
+        const data = res.data ?? {};
+        const details = data.accountStatementDetails;
+        const list = Array.isArray(details) ? details : [];
+        salesData.value = normalizeSalesRows(list);
+        applyStatementSummary(data);
+        statementDetailLoaded.value = true;
 
-    salesData.value = mockSalesData;
-
-    const lastPeriod = getLastPeriod(generateForm.period);
-    const lastStatement = mockData.find(item =>
-      item.customerId === generateForm.customerId && item.period === lastPeriod
-    );
-    generateForm.beginBalance = lastStatement ? lastStatement.endBalance : 0;
-
-    calculateSummary();
-
-    salesLoading.value = false;
-  }, 500);
-};
-
-const getLastPeriod = (period) => {
-  const [year, month] = period.split("-").map(Number);
-  if (month === 1) {
-    return `${year - 1}-12`;
-  }
-  return `${year}-${String(month - 1).padStart(2, "0")}`;
+        if (salesData.value.length > 0) {
+          selectAllSalesRows(true);
+        }
+      } else {
+        salesData.value = [];
+        statementDetailLoaded.value = false;
+        ElMessage.error(res.msg || "鏌ヨ瀵硅处鏄庣粏澶辫触");
+      }
+    })
+    .catch(() => {
+      salesData.value = [];
+      statementDetailLoaded.value = false;
+      ElMessage.error("鏌ヨ瀵硅处鏄庣粏澶辫触");
+    })
+    .finally(() => {
+      salesLoading.value = false;
+    });
 };
 
 const calculateSummary = () => {
   let receivable = 0;
   let receipt = 0;
 
-  selectedSales.value.forEach(item => {
-    if (item.type === "鍑哄簱") {
+  selectedSales.value.forEach((item) => {
+    if (item.type === 1) {
       receivable += item.amount;
-    } else if (item.type === "閫�璐�") {
+    } else if (item.type === 5) {
       receivable -= item.amount;
-    } else if (item.type === "鏀舵") {
+    } else if (item.type === 3) {
       receipt += item.amount;
     }
   });
 
-  generateForm.currentReceivable = receivable;
-  generateForm.currentReceipt = receipt;
+  generateForm.currentPlan = receivable;
+  generateForm.currentActually = receipt;
+  generateForm.closingBalance = calculateEndBalance(
+    generateForm.openingBalance,
+    generateForm.currentPlan,
+    generateForm.currentActually
+  );
 };
 
 const handleSalesSelectionChange = (selection) => {
@@ -342,51 +533,127 @@
 };
 
 const confirmGenerate = () => {
-  const newId = mockData.length > 0 ? Math.max(...mockData.map(item => item.id)) + 1 : 1;
-  const endBalance = calculateEndBalance(generateForm.beginBalance, generateForm.currentReceivable, generateForm.currentReceipt);
+  if (!canGenerate.value) return;
+  submitLoading.value = true;
+  addAccountStatement(buildAddPayload())
+    .then((res) => {
+      if (res.code === 200) {
+        generateDialogVisible.value = false;
+        ElMessage.success("瀵硅处鍗曠敓鎴愭垚鍔�");
+        pagination.currentPage = 1;
+        getTableData();
+      } else {
+        ElMessage.error(res.msg || "鐢熸垚澶辫触");
+      }
+    })
+    .catch(() => {
+      ElMessage.error("鐢熸垚澶辫触");
+    })
+    .finally(() => {
+      submitLoading.value = false;
+    });
+};
 
-  mockData.unshift({
-    id: newId,
-    statementCode: "DZ" + Date.now(),
-    customerId: generateForm.customerId,
-    customerName: generateForm.customerName,
-    period: generateForm.period,
-    beginBalance: generateForm.beginBalance,
-    currentReceivable: generateForm.currentReceivable,
-    currentReceipt: generateForm.currentReceipt,
-    endBalance,
+const handleDelete = (row) => {
+  ElMessageBox.confirm(`纭鍒犻櫎瀵硅处鍗曘��${row.statementNumber || row.id}銆嶅悧锛焋, "鎻愮ず", {
+    confirmButtonText: "纭畾",
+    cancelButtonText: "鍙栨秷",
+    type: "warning",
+  }).then(() => {
+    deleteAccountStatement([row.id])
+      .then((res) => {
+        if (res.code === 200) {
+          ElMessage.success("鍒犻櫎鎴愬姛");
+          getTableData();
+        } else {
+          ElMessage.error(res.msg || "鍒犻櫎澶辫触");
+        }
+      })
+      .catch(() => {
+        ElMessage.error("鍒犻櫎澶辫触");
+      });
+  });
+};
+
+const buildDetailTableFromApi = (data, statementMonth) => {
+  const details = Array.isArray(data.accountStatementDetails) ? data.accountStatementDetails : [];
+  let runningBalance = Number(data.openingBalance ?? 0);
+  const rows = [
+    {
+      date: statementMonth ?? "",
+      type: "鏈熷垵",
+      code: "-",
+      debit: 0,
+      credit: 0,
+      balance: runningBalance,
+      remark: "鏈熷垵浣欓",
+    },
+  ];
+
+  details.forEach((item) => {
+    const amount = Math.abs(Number(item.amount ?? 0));
+    const type = Number(item.type);
+    let debit = 0;
+    let credit = 0;
+
+    if (type === 1) {
+      debit = amount;
+      runningBalance += amount;
+    } else if (type === 3 || type === 5) {
+      credit = amount;
+      runningBalance -= amount;
+    }
+
+    rows.push({
+      date: item.occurrenceDate ?? "",
+      type: getDetailTypeLabel(type),
+      code: item.receiptNumber ?? "",
+      debit,
+      credit,
+      balance: runningBalance,
+      remark: item.remark ?? "",
+    });
   });
 
-  generateDialogVisible.value = false;
-  ElMessage.success("瀵硅处鍗曠敓鎴愭垚鍔�");
-  getTableData();
+  return rows;
 };
 
 const viewDetail = (row) => {
-  currentCustomer.value = row.customerName;
-  currentPeriod.value = row.period;
+  if (!row.customerId || !row.statementMonth) {
+    ElMessage.warning("缂哄皯瀹㈡埛鎴栧璐︽湀浠斤紝鏃犳硶鏌ヨ鏄庣粏");
+    return;
+  }
 
-  const saleOutAmount = Math.floor(row.currentReceivable * 0.6);
-  const returnAmount = Math.floor(row.currentReceivable * 0.1);
-  const firstReceipt = Math.floor(row.currentReceipt * 0.4);
-  const secondReceipt = row.currentReceipt - firstReceipt;
-
-  let runningBalance = row.beginBalance;
-
-  detailData.value = [
-    { date: row.period + "-01", type: "鏈熷垵", code: "-", debit: 0, credit: 0, balance: runningBalance, remark: "鏈熷垵浣欓" },
-    { date: row.period + "-05", type: "鍑哄簱", code: "CK2024001", debit: saleOutAmount, credit: 0, balance: runningBalance += saleOutAmount, remark: "閿�鍞嚭搴�" },
-    { date: row.period + "-10", type: "鏀舵", code: "SK2024001", debit: 0, credit: firstReceipt, balance: runningBalance -= firstReceipt, remark: "瀹㈡埛鍥炴" },
-    { date: row.period + "-15", type: "鍑哄簱", code: "CK2024002", debit: row.currentReceivable - saleOutAmount - returnAmount, credit: 0, balance: runningBalance += (row.currentReceivable - saleOutAmount - returnAmount), remark: "閿�鍞嚭搴�" },
-    { date: row.period + "-20", type: "閫�璐�", code: "TH2024001", debit: 0, credit: returnAmount, balance: runningBalance -= returnAmount, remark: "閿�鍞��璐�" },
-    { date: row.period + "-25", type: "鏀舵", code: "SK2024002", debit: 0, credit: secondReceipt, balance: runningBalance -= secondReceipt, remark: "瀹㈡埛鍥炴" },
-  ];
-
+  currentCustomer.value = row.customerName ?? "";
+  currentPeriod.value = row.statementMonth ?? "";
+  detailData.value = [];
   detailDialogVisible.value = true;
+  detailLoading.value = true;
+
+  getAccountStatementDetailsByMonth({
+    accountType: ACCOUNT_TYPE_RECEIVABLE,
+    customerId: row.customerId,
+    statementMonth: row.statementMonth,
+  })
+    .then((res) => {
+      if (res.code === 200) {
+        detailData.value = buildDetailTableFromApi(res.data ?? {}, row.statementMonth);
+      } else {
+        ElMessage.error(res.msg || "鏌ヨ鏄庣粏澶辫触");
+        detailDialogVisible.value = false;
+      }
+    })
+    .catch(() => {
+      ElMessage.error("鏌ヨ鏄庣粏澶辫触");
+      detailDialogVisible.value = false;
+    })
+    .finally(() => {
+      detailLoading.value = false;
+    });
 };
 
 const printStatement = (row) => {
-  ElMessage.info(`鎵撳嵃瀵硅处鍗�: ${row.statementCode}`);
+  ElMessage.info(`鎵撳嵃瀵硅处鍗�: ${row.statementNumber}`);
 };
 
 const printDetail = () => {
@@ -394,10 +661,12 @@
 };
 
 const handleOut = () => {
-  ElMessage.success("瀵煎嚭鎴愬姛");
+  const params = buildExportParams();
+  proxy.download("/accountStatement/exportAccountStatement", params, `搴旀敹瀵硅处鍗昣${Date.now()}.xlsx`);
 };
 
 onMounted(() => {
+  getCustomerList();
   getTableData();
 });
 </script>

--
Gitblit v1.9.3