From 261f2ed00235d47df3754291a4fdca9ba5cb8e7a Mon Sep 17 00:00:00 2001
From: spring <2396852758@qq.com>
Date: 星期四, 21 五月 2026 17:16:09 +0800
Subject: [PATCH] fix: 合并财务数据

---
 src/views/financialManagement/payable/reconciliation.vue |  666 +++++++++++++++++++++++++++++++++++++++++++++++++------
 1 files changed, 589 insertions(+), 77 deletions(-)

diff --git a/src/views/financialManagement/payable/reconciliation.vue b/src/views/financialManagement/payable/reconciliation.vue
index 06854b8..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,31 +42,31 @@
         }"
         @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>
 
-    <el-dialog title="瀵硅处鏄庣粏" v-model="detailDialogVisible" width="900px" append-to-body>
+    <FormDialog title="瀵硅处鏄庣粏" v-model="detailDialogVisible" width="900px" @confirm="printDetail" @cancel="detailDialogVisible = false" operationType="detail">
       <div class="statement-header">
         <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>
@@ -88,16 +95,111 @@
         <el-table-column prop="remark" label="澶囨敞" show-overflow-tooltip />
       </el-table>
       <template #footer>
-        <el-button @click="detailDialogVisible = false">鍏抽棴</el-button>
         <el-button type="primary" @click="printDetail">鎵撳嵃</el-button>
+        <el-button @click="detailDialogVisible = false">鍏抽棴</el-button>
       </template>
-    </el-dialog>
+    </FormDialog>
+
+    <FormDialog title="鐢熸垚瀵硅处鍗�" v-model="generateDialogVisible" width="1000px" @confirm="confirmGenerate" @cancel="generateDialogVisible = false">
+      <el-form :model="generateForm" label-width="100px">
+        <el-row :gutter="20">
+          <el-col :span="12">
+            <el-form-item label="閫夋嫨渚涘簲鍟�" prop="supplierId">
+              <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="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="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="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="getDetailTypeTagType(row.type)">{{ row.typeLabel }}</el-tag>
+            </template>
+          </el-table-column>
+          <el-table-column prop="amount" label="閲戦" width="120">
+            <template #default="{ row }">
+              <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.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 && generateForm.statementMonth && !purchaseLoading" class="empty-tip">
+        <el-empty description="璇ヤ緵搴斿晢鏈湀鏆傛棤閲囪喘鏁版嵁" />
+      </div>
+
+      <template #footer>
+        <el-button type="primary" @click="confirmGenerate" :disabled="!canGenerate" :loading="submitLoading">纭鐢熸垚</el-button>
+        <el-button @click="generateDialogVisible = false">鍙栨秷</el-button>
+      </template>
+    </FormDialog>
   </div>
 </template>
 
 <script setup>
-import { ref, reactive, onMounted } 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: "搴斾粯瀵硅处",
@@ -116,34 +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 supplierList = [
-  { id: 1, name: "鍖椾含鍘熸潗鏂欎緵搴斿晢" },
-  { id: 2, name: "涓婃捣鐢靛瓙鍏冨櫒浠跺叕鍙�" },
-  { id: 3, name: "骞垮窞鍖呰鏉愭枡鍘�" },
-  { id: 4, name: "娣卞湷浜旈噾閰嶄欢鍏徃" },
-];
+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([]);
 
-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 },
-];
+/** 鏄庣粏 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: "",
+  statementMonth: "",
+  openingBalance: 0,
+  currentPlan: 0,
+  currentActually: 0,
+  closingBalance: 0,
+});
+
+const displayClosingBalance = computed(() =>
+  calculateEndBalance(
+    generateForm.openingBalance,
+    generateForm.currentPlan,
+    generateForm.currentActually
+  )
+);
+
+const canGenerate = computed(
+  () => generateForm.supplierId && generateForm.statementMonth && selectedPurchases.value.length > 0
+);
+
+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";
@@ -151,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 = () => {
@@ -170,46 +450,235 @@
   getTableData();
 };
 
-const changePage = ({ current, size }) => {
-  pagination.currentPage = current;
-  pagination.pageSize = size;
+const changePage = ({ page, limit }) => {
+  pagination.currentPage = page;
+  pagination.pageSize = limit;
   getTableData();
 };
 
 const generateStatement = () => {
-  ElMessage.success("瀵硅处鍗曠敓鎴愭垚鍔�");
-  const newId = mockData.length > 0 ? Math.max(...mockData.map(item => item.id)) + 1 : 1;
-  const supplier = supplierList[Math.floor(Math.random() * supplierList.length)];
-  mockData.unshift({
-    id: newId,
-    statementCode: "DZ" + Date.now(),
-    supplierId: supplier.id,
-    supplierName: supplier.name,
-    period: "2024-03",
-    beginBalance: Math.floor(Math.random() * 20000),
-    currentPayable: Math.floor(Math.random() * 25000),
-    currentPayment: Math.floor(Math.random() * 20000),
-    endBalance: Math.floor(Math.random() * 25000),
+  generateForm.supplierId = "";
+  generateForm.supplierName = "";
+  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.value.find((item) => item.id === supplierId);
+  generateForm.supplierName = supplier?.supplierName ?? "";
+  loadPurchaseData();
+};
+
+const onStatementMonthChange = () => {
+  loadPurchaseData();
+};
+
+const loadPurchaseData = () => {
+  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;
+
+  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;
+
+        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 === 2) {
+      payable += item.amount;
+    } else if (item.type === 5) {
+      payable -= item.amount;
+    } else if (item.type === 4) {
+      payment += item.amount;
+    }
   });
-  getTableData();
+
+  generateForm.currentPlan = payable;
+  generateForm.currentActually = payment;
+  generateForm.closingBalance = calculateEndBalance(
+    generateForm.openingBalance,
+    generateForm.currentPlan,
+    generateForm.currentActually
+  );
+};
+
+const handlePurchaseSelectionChange = (selection) => {
+  selectedPurchases.value = selection;
+  calculateSummary();
+};
+
+const confirmGenerate = () => {
+  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;
+    });
+};
+
+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 ?? "",
+    });
+  });
+
+  return rows;
 };
 
 const viewDetail = (row) => {
-  currentSupplier.value = row.supplierName;
-  currentPeriod.value = row.period;
-  detailData.value = [
-    { date: row.period + "-01", type: "鏈熷垵", code: "-", debit: 0, credit: 0, balance: row.beginBalance, remark: "鏈熷垵浣欓" },
-    { date: row.period + "-05", type: "鍏ュ簱", code: "RK2024001", debit: 0, credit: 8000, balance: row.beginBalance + 8000, remark: "" },
-    { date: row.period + "-10", type: "浠樻", code: "FK2024001", debit: 5000, credit: 0, balance: row.beginBalance + 3000, remark: "" },
-    { date: row.period + "-15", type: "鍏ュ簱", code: "RK2024002", credit: 12000, balance: row.beginBalance + 15000, remark: "" },
-    { date: row.period + "-20", type: "閫�璐�", code: "TH2024001", debit: 2000, credit: 0, balance: row.beginBalance + 13000, remark: "" },
-    { date: row.period + "-25", type: "浠樻", code: "FK2024002", debit: row.currentPayment - 5000, balance: row.endBalance, remark: "" },
-  ];
-  detailDialogVisible.value = true;
-};
+  const partnerId = row.customerId ?? row.supplierId;
+  if (!partnerId || !row.statementMonth) {
+    ElMessage.warning("缂哄皯渚涘簲鍟嗘垨瀵硅处鏈堜唤锛屾棤娉曟煡璇㈡槑缁�");
+    return;
+  }
 
-const printStatement = (row) => {
-  ElMessage.info(`鎵撳嵃瀵硅处鍗�: ${row.statementCode}`);
+  currentSupplier.value = row.supplierName ?? row.customerName ?? "";
+  currentPeriod.value = row.statementMonth ?? "";
+  detailData.value = [];
+  detailDialogVisible.value = true;
+  detailLoading.value = true;
+
+  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 = () => {
@@ -217,10 +686,15 @@
 };
 
 const handleOut = () => {
-  ElMessage.success("瀵煎嚭鎴愬姛");
+  proxy.download(
+    "/accountStatement/exportAccountStatement",
+    buildExportParams(),
+    `搴斾粯瀵硅处鍗昣${Date.now()}.xlsx`
+  );
 };
 
 onMounted(() => {
+  getSupplierList();
   getTableData();
 });
 </script>
@@ -240,6 +714,10 @@
   color: #f56c6c;
 }
 
+.text-primary {
+  color: #409eff;
+}
+
 .statement-header {
   text-align: center;
   margin-bottom: 20px;
@@ -251,4 +729,38 @@
     margin: 0;
   }
 }
+
+.purchase-section {
+  margin-top: 20px;
+
+  .section-title {
+    font-size: 16px;
+    font-weight: bold;
+    margin-bottom: 15px;
+    padding-left: 10px;
+    border-left: 4px solid #409eff;
+  }
+}
+
+.summary-row {
+  display: flex;
+  justify-content: space-around;
+  padding: 15px;
+  background-color: #f5f7fa;
+  border-radius: 4px;
+  margin-top: 15px;
+
+  span {
+    font-size: 14px;
+
+    strong {
+      font-size: 16px;
+      margin-left: 5px;
+    }
+  }
+}
+
+.empty-tip {
+  margin-top: 30px;
+}
 </style>

--
Gitblit v1.9.3