From 32a35a2ae4cd198335788866181c7aa4579cc90d Mon Sep 17 00:00:00 2001
From: gaoluyang <2820782392@qq.com>
Date: 星期五, 16 一月 2026 14:53:41 +0800
Subject: [PATCH] 进销存-升级 1.修改上传组件bug 2.付款流水和回款流水添加删除功能 3.调整财务管理页面样式和运用组件

---
 src/views/financialManagement/expenseManagement/index.vue |  187 ++++++++
 src/views/procurementManagement/paymentHistory/index.vue  |   87 ++++
 /dev/null                                                 |  202 ----------
 src/views/financialManagement/expenseManagement/Modal.vue |  192 +++++++--
 src/components/PIMTable/PIMTable.vue                      |    2 
 src/views/financialManagement/loanManagement/index.vue    |    9 
 src/views/financialManagement/revenueManagement/index.vue |  191 ++++++++-
 src/views/procurementManagement/paymentEntry/index.vue    |    2 
 src/views/financialManagement/revenueManagement/Modal.vue |  192 +++++++--
 src/components/Dialog/FileListDialog.vue                  |    7 
 src/views/salesManagement/receiptPaymentHistory/index.vue |   91 ++++
 11 files changed, 819 insertions(+), 343 deletions(-)

diff --git a/src/components/Dialog/FileListDialog.vue b/src/components/Dialog/FileListDialog.vue
index ebe81dd..0721a55 100644
--- a/src/components/Dialog/FileListDialog.vue
+++ b/src/components/Dialog/FileListDialog.vue
@@ -229,10 +229,9 @@
 
 const handleUpload = async () => {
   if (props.uploadMethod) {
-    const newItem = await props.uploadMethod()
-    if (newItem) {
-      addAttachment(newItem)
-    }
+    // 濡傛灉鎻愪緵浜嗚嚜瀹氫箟涓婁紶鏂规硶锛岀敱鐖剁粍浠惰礋璐f洿鏂板垪琛紙閫氳繃 setList锛�
+    // 杩欓噷涓嶅啀鑷姩娣诲姞锛岄伩鍏嶄笌鐖剁粍浠剁殑 setList 閲嶅
+    await props.uploadMethod()
   }
   emit('upload')
 }
diff --git a/src/components/PIMTable/PIMTable.vue b/src/components/PIMTable/PIMTable.vue
index 01462f0..1480893 100644
--- a/src/components/PIMTable/PIMTable.vue
+++ b/src/components/PIMTable/PIMTable.vue
@@ -40,7 +40,7 @@
       :fixed="item.fixed"
       :label="item.label"
       :prop="item.prop"
-      :show-overflow-tooltip="item.dataType !== 'action'"
+      :show-overflow-tooltip="item.dataType !== 'action' && item.dataType !== 'slot'"
       :align="item.align"
       :sortable="!!item.sortable"
       :type="item.type"
diff --git a/src/views/financialManagement/expenseManagement/Form.vue b/src/views/financialManagement/expenseManagement/Form.vue
deleted file mode 100644
index 9cfe5da..0000000
--- a/src/views/financialManagement/expenseManagement/Form.vue
+++ /dev/null
@@ -1,123 +0,0 @@
-<template>
-  <el-form :model="form" label-width="100px" :rules="formRules" ref="formRef">
-    <el-form-item label="鏀嚭鏃ユ湡" prop="expenseDate">
-          <el-date-picker
-            style="width: 100%"
-            v-model="form.expenseDate"
-            format="YYYY-MM-DD"
-            value-format="YYYY-MM-DD"
-            type="date"
-            placeholder="璇烽�夋嫨鏃ユ湡"
-            clearable
-          />
-        </el-form-item>
-        <el-form-item label="鏀嚭绫诲瀷" prop="expenseType">
-          <el-select
-            v-model="form.expenseType"
-            placeholder="璇烽�夋嫨"
-            clearable
-          >
-            <el-option :label="item.label" :value="item.value" v-for="(item,index) in expense_types" :key="index" />
-          </el-select>
-        </el-form-item>
-        <el-form-item label="渚涘簲鍟嗗悕绉�" prop="supplierName">
-          <el-input v-model="form.supplierName" placeholder="璇疯緭鍏�" />
-        </el-form-item>
-        <el-form-item label="鏀嚭閲戦" prop="expenseMoney">
-          <el-input-number :step="0.01" :min="0" style="width: 100%"
-            v-model="form.expenseMoney"
-            placeholder="璇疯緭鍏�"
-          />
-        </el-form-item>
-        <el-form-item label="鏀嚭鎻忚堪" prop="expenseDescribed">
-          <el-input v-model="form.expenseDescribed" placeholder="璇疯緭鍏�" />
-        </el-form-item>
-        <el-form-item label="浠樻鏂瑰紡" prop="expenseMethod">
-          <el-select
-            v-model="form.expenseMethod"
-            placeholder="璇烽�夋嫨"
-            clearable
-          >
-            <el-option :label="item.label" :value="item.value" v-for="(item,index) in checkout_payment" :key="index" />
-          </el-select>
-        </el-form-item>
-        <el-form-item label="鍙戠エ鍙风爜" prop="invoiceNumber">
-          <el-input v-model="form.invoiceNumber" placeholder="璇疯緭鍏�" />
-        </el-form-item>
-        <el-form-item label="澶囨敞" prop="note">
-          <el-input
-            v-model="form.note"
-            placeholder="澶囨敞"
-          />
-        </el-form-item>
-        
-  </el-form>
-</template>
-
-<script setup>
-import useFormData from "@/hooks/useFormData";
-import { getAccountExpense } from "@/api/financialManagement/expenseManagement";
-import {ref} from "vue";
-const { proxy } = getCurrentInstance();
-
-
-defineOptions({
-  name: "鏂板鏀嚭",
-});
-const { expense_types } = proxy.useDict("expense_types");
-const { checkout_payment } = proxy.useDict("checkout_payment");
-const formRef = ref(null);
-const formRules = {
-	supplierName: [{ required: true, trigger: "blur", message: "璇疯緭鍏�" }],
-	expenseMoney: [{ required: true, trigger: "blur", message: "璇疯緭鍏�" }],
-	expenseDescribed: [{ required: true, trigger: "blur", message: "璇疯緭鍏�" }],
-	expenseDate: [{ required: true, trigger: "change", message: "璇烽�夋嫨" }],
-  expenseType: [{ required: true, trigger: "change", message: "璇烽�夋嫨" }],
-  expenseMethod: [{ required: true, trigger: "change", message: "璇烽�夋嫨" }],
-}
-
-const { form, resetForm } = useFormData({
-  expenseDate: undefined, // 鏀嚭鏃ユ湡
-  expenseType: undefined, // 鏀嚭绫诲瀷
-  supplierName: undefined, // 瀹㈡埛鍚嶇О
-  expenseMoney: undefined, // 鏀嚭閲戦
-  expenseDescribed: undefined, // 鏀嚭鎻忚堪
-  expenseMethod: undefined, // 鏀舵鏂瑰紡
-  invoiceNumber: undefined, // 鍙戠エ鍙风爜
-  note: undefined, // 澶囨敞
-});
-
-const loadForm = async (id) => {
-  const { code, data } = await getAccountExpense(id);
-  if (code == 200) {
-    form.expenseDate = data.expenseDate;
-    form.expenseType = data.expenseType;
-    form.supplierName = data.supplierName;
-    form.expenseMoney = data.expenseMoney;
-    form.expenseDescribed = data.expenseDescribed;
-    form.expenseMethod = data.expenseMethod;
-    form.invoiceNumber = data.invoiceNumber;
-    form.note = data.note;
-  }
-};
-
-// 娓呴櫎琛ㄥ崟鏍¢獙鐘舵��
-const clearValidate = () => {
-  formRef.value?.clearValidate();
-};
-
-// 閲嶇疆琛ㄥ崟鏁版嵁鍜屾牎楠岀姸鎬�
-const resetFormAndValidate = () => {
-  resetForm();
-  clearValidate();
-};
-
-defineExpose({
-  form,
-  loadForm,
-  resetForm,
-  clearValidate,
-  resetFormAndValidate,
-	formRef,
-});
-</script>
diff --git a/src/views/financialManagement/expenseManagement/Modal.vue b/src/views/financialManagement/expenseManagement/Modal.vue
index 8e5b171..4d743c1 100644
--- a/src/views/financialManagement/expenseManagement/Modal.vue
+++ b/src/views/financialManagement/expenseManagement/Modal.vue
@@ -1,20 +1,75 @@
 <template>
-  <el-dialog :title="modalOptions.title" v-model="visible" @close="close" width="30%">
-    <Form ref="formRef"></Form>
-    <template #footer>
-			<el-button type="primary" @click="sendForm" :loading="loading">
-				{{ modalOptions.confirmText }}
-			</el-button>
-      <el-button @click="closeModal">{{ modalOptions.cancelText }}</el-button>
-    </template>
-  </el-dialog>
+  <FormDialog
+    v-model="dialogVisible"
+    :title="dialogTitle"
+    :operationType="operationType"
+    width="50%"
+    @confirm="sendForm"
+    @close="close"
+    @cancel="close"
+  >
+    <el-form :model="form" label-width="100px" :rules="formRules" ref="formRef">
+      <el-form-item label="鏀嚭鏃ユ湡" prop="expenseDate">
+        <el-date-picker
+          style="width: 100%"
+          v-model="form.expenseDate"
+          format="YYYY-MM-DD"
+          value-format="YYYY-MM-DD"
+          type="date"
+          placeholder="璇烽�夋嫨鏃ユ湡"
+          clearable
+        />
+      </el-form-item>
+      <el-form-item label="鏀嚭绫诲瀷" prop="expenseType">
+        <el-select
+          v-model="form.expenseType"
+          placeholder="璇烽�夋嫨"
+          clearable
+        >
+          <el-option :label="item.label" :value="item.value" v-for="(item,index) in expense_types" :key="index" />
+        </el-select>
+      </el-form-item>
+      <el-form-item label="渚涘簲鍟嗗悕绉�" prop="supplierName">
+        <el-input v-model="form.supplierName" placeholder="璇疯緭鍏�" />
+      </el-form-item>
+      <el-form-item label="鏀嚭閲戦" prop="expenseMoney">
+        <el-input-number :step="0.01" :min="0" style="width: 100%"
+          v-model="form.expenseMoney"
+          placeholder="璇疯緭鍏�"
+        />
+      </el-form-item>
+      <el-form-item label="鏀嚭鎻忚堪" prop="expenseDescribed">
+        <el-input v-model="form.expenseDescribed" placeholder="璇疯緭鍏�" />
+      </el-form-item>
+      <el-form-item label="浠樻鏂瑰紡" prop="expenseMethod">
+        <el-select
+          v-model="form.expenseMethod"
+          placeholder="璇烽�夋嫨"
+          clearable
+        >
+          <el-option :label="item.label" :value="item.value" v-for="(item,index) in checkout_payment" :key="index" />
+        </el-select>
+      </el-form-item>
+      <el-form-item label="鍙戠エ鍙风爜" prop="invoiceNumber">
+        <el-input v-model="form.invoiceNumber" placeholder="璇疯緭鍏�" />
+      </el-form-item>
+      <el-form-item label="澶囨敞" prop="note">
+        <el-input
+          v-model="form.note"
+          placeholder="澶囨敞"
+        />
+      </el-form-item>
+    </el-form>
+  </FormDialog>
 </template>
 
 <script setup>
-import { useModal } from "@/hooks/useModal";
-import { add, update } from "@/api/financialManagement/expenseManagement";
-import Form from "./Form.vue";
+import { add, update, getAccountExpense } from "@/api/financialManagement/expenseManagement";
 import { ElMessage } from "element-plus";
+import useFormData from "@/hooks/useFormData";
+import FormDialog from "@/components/Dialog/FormDialog.vue";
+import { ref } from "vue";
+
 const { proxy } = getCurrentInstance()
 
 defineOptions({
@@ -23,43 +78,96 @@
 
 const emits = defineEmits(["success"]);
 
-const formRef = ref();
-const {
-  id,
-  visible,
-  loading,
-  openModal,
-  modalOptions,
-  handleConfirm,
-  closeModal,
-} = useModal({ title: "鏀嚭" });
+const formRef = ref(null);
+const dialogVisible = ref(false);
+const operationType = ref("add"); // add | edit
+const id = ref(undefined);
+const submitting = ref(false);
+
+const dialogTitle = (type) => {
+  if (type === "edit") return "缂栬緫鏀嚭";
+  return "鏂板鏀嚭";
+};
+
+const { expense_types } = proxy.useDict("expense_types");
+const { checkout_payment } = proxy.useDict("checkout_payment");
+
+const formRules = {
+  supplierName: [{ required: true, trigger: "blur", message: "璇疯緭鍏�" }],
+  expenseMoney: [{ required: true, trigger: "blur", message: "璇疯緭鍏�" }],
+  expenseDescribed: [{ required: true, trigger: "blur", message: "璇疯緭鍏�" }],
+  expenseDate: [{ required: true, trigger: "change", message: "璇烽�夋嫨" }],
+  expenseType: [{ required: true, trigger: "change", message: "璇烽�夋嫨" }],
+  expenseMethod: [{ required: true, trigger: "change", message: "璇烽�夋嫨" }],
+}
+
+const { form, resetForm } = useFormData({
+  expenseDate: undefined, // 鏀嚭鏃ユ湡
+  expenseType: undefined, // 鏀嚭绫诲瀷
+  supplierName: undefined, // 渚涘簲鍟嗗悕绉�
+  expenseMoney: undefined, // 鏀嚭閲戦
+  expenseDescribed: undefined, // 鏀嚭鎻忚堪
+  expenseMethod: undefined, // 浠樻鏂瑰紡
+  invoiceNumber: undefined, // 鍙戠エ鍙风爜
+  note: undefined, // 澶囨敞
+});
 
 const sendForm = () => {
-	proxy.$refs.formRef.$refs.formRef.validate(async valid => {
-		if (valid) {
-			const {code} = id.value
-				? await update({id: id.value, ...formRef.value.form})
-				: await add(formRef.value.form);
-			if (code == 200) {
-				emits("success");
-				ElMessage({message: "鎿嶄綔鎴愬姛", type: "success"});
-				close();
-			} else {
-				loading.value = false;
-			}
-		}
-	})
+  if (submitting.value) return;
+  formRef.value?.validate(async (valid) => {
+    if (valid) {
+      submitting.value = true;
+      try {
+        const { code } = id.value
+          ? await update({ id: id.value, ...form })
+          : await add(form);
+        if (code == 200) {
+          emits("success");
+          ElMessage({ message: "鎿嶄綔鎴愬姛", type: "success" });
+          close();
+        }
+      } finally {
+        submitting.value = false;
+      }
+    }
+  })
 };
 
 const close = () => {
-	formRef.value.resetFormAndValidate();
-  closeModal();
+  resetForm();
+  formRef.value?.clearValidate();
+  id.value = undefined;
+  dialogVisible.value = false;
 };
 
-const loadForm = async (id) => {
-  openModal(id);
-  await nextTick();
-  formRef.value.loadForm(id);
+const loadForm = async (rowId) => {
+  operationType.value = "edit";
+  id.value = rowId;
+  dialogVisible.value = true;
+  if (rowId) {
+    const { code, data } = await getAccountExpense(rowId);
+    if (code == 200) {
+      form.expenseDate = data.expenseDate;
+      form.expenseType = data.expenseType;
+      form.supplierName = data.supplierName;
+      form.expenseMoney = data.expenseMoney;
+      form.expenseDescribed = data.expenseDescribed;
+      form.expenseMethod = data.expenseMethod;
+      form.invoiceNumber = data.invoiceNumber;
+      form.note = data.note;
+    }
+  } else {
+    resetForm();
+    formRef.value?.clearValidate();
+  }
+};
+
+const openModal = () => {
+  operationType.value = "add";
+  id.value = undefined;
+  resetForm();
+  formRef.value?.clearValidate();
+  dialogVisible.value = true;
 };
 
 defineExpose({
diff --git a/src/views/financialManagement/expenseManagement/index.vue b/src/views/financialManagement/expenseManagement/index.vue
index a45c32d..2f84e84 100644
--- a/src/views/financialManagement/expenseManagement/index.vue
+++ b/src/views/financialManagement/expenseManagement/index.vue
@@ -55,12 +55,12 @@
         @pagination="changePage"
       >
         <template #operation="{ row }">
-          <el-button type="primary" text @click="edit(row.id)" icon="editPen">
+          <el-button type="primary" link @click="edit(row.id)">
             缂栬緫
           </el-button>
           <el-button
             type="primary"
-            text
+            link
             @click="openFilesFormDia(row)"
           >
             闄勪欢
@@ -69,18 +69,27 @@
       </PIMTable>
     </div>
     <Modal ref="modalRef" @success="getTableData"></Modal>
-    <files-dia ref="filesDia"></files-dia>
+    <FileListDialog 
+      ref="fileListRef" 
+      v-model="fileListDialogVisible"
+      :show-upload-button="true"
+      :show-delete-button="true"
+      :upload-method="handleUpload"
+      :delete-method="handleFileDelete"
+    />
   </div>
 </template>
 
 <script setup>
 import { usePaginationApi } from "@/hooks/usePaginationApi";
-import { listPage, delAccountExpense } from "@/api/financialManagement/expenseManagement";
+import { listPage, delAccountExpense, fileListPage, fileAdd, fileDel } from "@/api/financialManagement/expenseManagement";
 import { onMounted, getCurrentInstance } from "vue";
 import Modal from "./Modal.vue";
 import { ElMessageBox, ElMessage } from "element-plus";
 import dayjs from "dayjs";
-import FilesDia from "../revenueManagement/filesDia.vue";
+import FileListDialog from "@/components/Dialog/FileListDialog.vue";
+import request from "@/utils/request";
+import { getToken } from "@/utils/auth";
 
 defineOptions({
   name: "鏀嚭绠$悊",
@@ -92,7 +101,10 @@
 const modalRef = ref();
 const { checkout_payment } = proxy.useDict("checkout_payment");
 const { expense_types } = proxy.useDict("expense_types");
-const filesDia = ref()
+const fileListRef = ref(null);
+const fileListDialogVisible = ref(false);
+const currentFileRow = ref(null);
+const accountType = ref('鏀嚭');
 
 const {
   filters,
@@ -111,7 +123,6 @@
   [
     {
       label: "鏀嚭鏃ユ湡",
-      align: "center",
       prop: "expenseDate",
     },
     {
@@ -129,19 +140,16 @@
     },
     {
       label: "渚涘簲鍟嗗悕绉�",
-      align: "center",
       prop: "supplierName",
 
     },
     {
       label: "鏀嚭閲戦",
-      align: "center",
       prop: "expenseMoney",
 
     },
     {
       label: "鏀嚭鎻忚堪",
-      align: "center",
       prop: "expenseDescribed",
 
     },
@@ -149,6 +157,7 @@
       label: "浠樻鏂瑰紡",
       align: "center",
       prop: "expenseMethod",
+			width: '120',
       dataType: "tag",
       formatData: (params) => {
         if (checkout_payment.value.find((m) => m.value == params)) {
@@ -160,24 +169,20 @@
     },
     {
       label: "鍙戠エ鍙风爜",
-      align: "center",
       prop: "invoiceNumber",
 
     },
     {
       label: "澶囨敞",
-      align: "center",
       prop: "note",
 
     },
     {
       label: "褰曞叆浜�",
-      align: "center",
       prop: "inputUser",
     },
     {
       label: "褰曞叆鏃ユ湡",
-      align: "center",
       prop: "inputTime",
 
     },
@@ -187,7 +192,7 @@
       dataType: "slot",
       slot: "operation",
       align: "center",
-      width: "200px",
+      width: "160px",
     },
   ]
 );
@@ -252,10 +257,154 @@
     });
 };
 // 鎵撳紑闄勪欢寮规
-const openFilesFormDia = (row) => {
-  nextTick(() => {
-    filesDia.value?.openDialog( row,'鏀嚭')
-  })
+const openFilesFormDia = async (row) => {
+  currentFileRow.value = row;
+  accountType.value = '鏀嚭';
+  try {
+    const res = await fileListPage({
+      accountId: row.id,
+      accountType: accountType.value,
+      current: 1,
+      size: 100
+    });
+    if (res.code === 200 && fileListRef.value) {
+      // 灏嗘暟鎹浆鎹负 FileListDialog 闇�瑕佺殑鏍煎紡
+      const fileList = (res.data?.records || []).map(item => ({
+        name: item.name,
+        url: item.url,
+        id: item.id,
+        ...item
+      }));
+      fileListRef.value.open(fileList);
+      fileListDialogVisible.value = true;
+    }
+  } catch (error) {
+    proxy.$modal.msgError("鑾峰彇闄勪欢鍒楄〃澶辫触");
+  }
+};
+
+// 涓婁紶闄勪欢
+const handleUpload = async () => {
+  if (!currentFileRow.value) {
+    proxy.$modal.msgWarning("璇峰厛閫夋嫨鏁版嵁");
+    return null;
+  }
+  
+  return new Promise((resolve) => {
+    // 鍒涘缓涓�涓殣钘忕殑鏂囦欢杈撳叆鍏冪礌
+    const input = document.createElement('input');
+    input.type = 'file';
+    input.style.display = 'none';
+    input.onchange = async (e) => {
+      const file = e.target.files[0];
+      if (!file) {
+        resolve(null);
+        return;
+      }
+      
+      try {
+        // 浣跨敤 FormData 涓婁紶鏂囦欢
+        const formData = new FormData();
+        formData.append('file', file);
+        
+        const uploadRes = await request({
+          url: '/file/upload',
+          method: 'post',
+          data: formData,
+          headers: {
+            'Content-Type': 'multipart/form-data',
+            Authorization: `Bearer ${getToken()}`
+          }
+        });
+        
+        if (uploadRes.code === 200) {
+          // 淇濆瓨闄勪欢淇℃伅
+          const fileData = {
+            accountId: currentFileRow.value.id,
+            accountType: accountType.value,
+            name: uploadRes.data.originalName || file.name,
+            url: uploadRes.data.tempPath || uploadRes.data.url
+          };
+          
+          const saveRes = await fileAdd(fileData);
+          if (saveRes.code === 200) {
+            proxy.$modal.msgSuccess("鏂囦欢涓婁紶鎴愬姛");
+            // 閲嶆柊鍔犺浇鏂囦欢鍒楄〃
+            const listRes = await fileListPage({
+              accountId: currentFileRow.value.id,
+              accountType: accountType.value,
+              current: 1,
+              size: 100
+            });
+            if (listRes.code === 200 && fileListRef.value) {
+              const fileList = (listRes.data?.records || []).map(item => ({
+                name: item.name,
+                url: item.url,
+                id: item.id,
+                ...item
+              }));
+              fileListRef.value.setList(fileList);
+            }
+            // 杩斿洖鏂版枃浠朵俊鎭�
+            resolve({
+              name: fileData.name,
+              url: fileData.url,
+              id: saveRes.data?.id
+            });
+          } else {
+            proxy.$modal.msgError(saveRes.msg || "鏂囦欢淇濆瓨澶辫触");
+            resolve(null);
+          }
+        } else {
+          proxy.$modal.msgError(uploadRes.msg || "鏂囦欢涓婁紶澶辫触");
+          resolve(null);
+        }
+      } catch (error) {
+        proxy.$modal.msgError("鏂囦欢涓婁紶澶辫触");
+        resolve(null);
+      } finally {
+        document.body.removeChild(input);
+      }
+    };
+    
+    document.body.appendChild(input);
+    input.click();
+  });
+};
+
+// 鍒犻櫎闄勪欢
+const handleFileDelete = async (row) => {
+  try {
+    const res = await fileDel([row.id]);
+    if (res.code === 200) {
+      proxy.$modal.msgSuccess("鍒犻櫎鎴愬姛");
+      // 閲嶆柊鍔犺浇鏂囦欢鍒楄〃
+      if (currentFileRow.value && fileListRef.value) {
+        const listRes = await fileListPage({
+          accountId: currentFileRow.value.id,
+          accountType: accountType.value,
+          current: 1,
+          size: 100
+        });
+        if (listRes.code === 200) {
+          const fileList = (listRes.data?.records || []).map(item => ({
+            name: item.name,
+            url: item.url,
+            id: item.id,
+            ...item
+          }));
+          fileListRef.value.setList(fileList);
+        }
+      }
+      return true; // 杩斿洖 true 琛ㄧず鍒犻櫎鎴愬姛锛岀粍浠朵細鏇存柊鍒楄〃
+    } else {
+      proxy.$modal.msgError(res.msg || "鍒犻櫎澶辫触");
+      return false;
+    }
+  } catch (error) {
+    proxy.$modal.msgError("鍒犻櫎澶辫触");
+    return false;
+  }
 };
 
 onMounted(() => {
diff --git a/src/views/financialManagement/loanManagement/index.vue b/src/views/financialManagement/loanManagement/index.vue
index 202313a..7580d3b 100644
--- a/src/views/financialManagement/loanManagement/index.vue
+++ b/src/views/financialManagement/loanManagement/index.vue
@@ -72,7 +72,7 @@
             缂栬緫
           </el-button>
           <el-button
-            v-if="row.status == 1"
+            :disabled="row.status !== 1"
             type="primary"
             link
             @click="repay(row)"
@@ -122,12 +122,10 @@
     {
       label: "鍊熸浜哄鍚�",
       prop: "borrowerName",
-      width: 150,
     },
     {
       label: "鍊熸閲戦锛堝厓锛�",
       prop: "borrowAmount",
-      width: 150,
       formatData: (val) => {
         return val ? `楼${parseFloat(val).toLocaleString('zh-CN', { minimumFractionDigits: 2, maximumFractionDigits: 2 })}` : '楼0.00';
       },
@@ -135,7 +133,6 @@
     {
       label: "鍊熸鍒╃巼锛�%锛�",
       prop: "interestRate",
-      width: 130,
       formatData: (val) => {
         return val ? `${parseFloat(val).toFixed(2)}%` : '-';
       },
@@ -143,18 +140,16 @@
     {
       label: "鍊熸鏃ユ湡",
       prop: "borrowDate",
-      width: 120,
     },
     {
       label: "瀹為檯杩樻鏃ユ湡",
       prop: "repayDate",
-      width: 130,
     },
     {
       label: "鍊熸鐘舵��",
       prop: "status",
-      width: 100,
       dataType: "tag",
+			align: 'center',
       formatData: (params) => {
         if (params == 1) {
           return "寰呰繕娆�";
diff --git a/src/views/financialManagement/revenueManagement/Form.vue b/src/views/financialManagement/revenueManagement/Form.vue
deleted file mode 100644
index 67b175e..0000000
--- a/src/views/financialManagement/revenueManagement/Form.vue
+++ /dev/null
@@ -1,123 +0,0 @@
-<template>
-  <el-form :model="form" label-width="100px" :rules="formRules" ref="formRef">
-    <el-form-item label="鏀跺叆鏃ユ湡" prop="incomeDate">
-          <el-date-picker
-            style="width: 100%"
-            v-model="form.incomeDate"
-            format="YYYY-MM-DD"
-            value-format="YYYY-MM-DD"
-            type="date"
-            placeholder="璇烽�夋嫨鏃ユ湡"
-            clearable
-          />
-        </el-form-item>
-        <el-form-item label="鏀跺叆绫诲瀷" prop="incomeType">
-          <el-select
-            v-model="form.incomeType"
-            placeholder="璇烽�夋嫨"
-            clearable
-          >
-            <el-option :label="item.label" :value="item.value" v-for="(item,index) in income_types" :key="index" />
-          </el-select>
-        </el-form-item>
-        <el-form-item label="瀹㈡埛鍚嶇О" prop="customerName">
-          <el-input v-model="form.customerName" placeholder="璇疯緭鍏�" />
-        </el-form-item>
-        <el-form-item label="鏀跺叆閲戦" prop="incomeMoney">
-          <el-input-number :step="0.01" :min="0" style="width: 100%"
-            v-model="form.incomeMoney"
-            placeholder="璇疯緭鍏�"
-          />
-        </el-form-item>
-        <el-form-item label="鏀跺叆鎻忚堪" prop="incomeDescribed">
-          <el-input v-model="form.incomeDescribed" placeholder="璇疯緭鍏�" />
-        </el-form-item>
-        <el-form-item label="鏀舵鏂瑰紡" prop="incomeMethod">
-          <el-select
-            v-model="form.incomeMethod"
-            placeholder="璇烽�夋嫨"
-            clearable
-          >
-            <el-option :label="item.label" :value="item.value" v-for="(item,index) in payment_methods" :key="index" />
-          </el-select>
-        </el-form-item>
-        <el-form-item label="鍙戠エ鍙风爜" prop="invoiceNumber">
-          <el-input v-model="form.invoiceNumber" placeholder="璇疯緭鍏�" />
-        </el-form-item>
-        <el-form-item label="澶囨敞" prop="note">
-          <el-input
-            v-model="form.note"
-            placeholder="澶囨敞"
-          />
-        </el-form-item>
-        
-  </el-form>
-</template>
-
-<script setup>
-import useFormData from "@/hooks/useFormData";
-import { getAccountIncome } from "@/api/financialManagement/revenueManagement";
-import {ref} from "vue";
-const { proxy } = getCurrentInstance();
-
-
-defineOptions({
-  name: "鏂板鏀跺叆",
-});
-const { income_types } = proxy.useDict("income_types");
-const { payment_methods } = proxy.useDict("payment_methods");
-const formRef = ref(null);
-const formRules = {
-	customerName: [{ required: true, trigger: "blur", message: "璇疯緭鍏�" }],
-	incomeMoney: [{ required: true, trigger: "blur", message: "璇疯緭鍏�" }],
-	incomeDescribed: [{ required: true, trigger: "blur", message: "璇疯緭鍏�" }],
-	incomeDate: [{ required: true, trigger: "change", message: "璇烽�夋嫨" }],
-  incomeType: [{ required: true, trigger: "change", message: "璇烽�夋嫨" }],
-  incomeMethod: [{ required: true, trigger: "change", message: "璇烽�夋嫨" }],
-}
-
-const { form, resetForm } = useFormData({
-  incomeDate: undefined, // 鏀跺叆鏃ユ湡
-  incomeType: undefined, // 鏀跺叆绫诲瀷
-  customerName: undefined, // 瀹㈡埛鍚嶇О
-  incomeMoney: undefined, // 鏀跺叆閲戦
-  incomeDescribed: undefined, // 鏀跺叆鎻忚堪
-  incomeMethod: undefined, // 鏀舵鏂瑰紡
-  invoiceNumber: undefined, // 鍙戠エ鍙风爜
-  note: undefined, // 澶囨敞
-});
-
-const loadForm = async (id) => {
-  const { code, data } = await getAccountIncome(id);
-  if (code == 200) {
-    form.incomeDate = data.incomeDate;
-    form.incomeType = data.incomeType;
-    form.customerName = data.customerName;
-    form.incomeMoney = data.incomeMoney;
-    form.incomeDescribed = data.incomeDescribed;
-    form.incomeMethod = data.incomeMethod;
-    form.invoiceNumber = data.invoiceNumber;
-    form.note = data.note;
-  }
-};
-
-// 娓呴櫎琛ㄥ崟鏍¢獙鐘舵��
-const clearValidate = () => {
-  formRef.value?.clearValidate();
-};
-
-// 閲嶇疆琛ㄥ崟鏁版嵁鍜屾牎楠岀姸鎬�
-const resetFormAndValidate = () => {
-  resetForm();
-  clearValidate();
-};
-
-defineExpose({
-  form,
-  loadForm,
-  resetForm,
-  clearValidate,
-  resetFormAndValidate,
-	formRef,
-});
-</script>
diff --git a/src/views/financialManagement/revenueManagement/Modal.vue b/src/views/financialManagement/revenueManagement/Modal.vue
index 480b4fd..245cdf2 100644
--- a/src/views/financialManagement/revenueManagement/Modal.vue
+++ b/src/views/financialManagement/revenueManagement/Modal.vue
@@ -1,20 +1,75 @@
 <template>
-  <el-dialog :title="modalOptions.title" v-model="visible" @close="close" width="30%">
-    <Form ref="formRef"></Form>
-    <template #footer>
-			<el-button type="primary" @click="sendForm" :loading="loading">
-				{{ modalOptions.confirmText }}
-			</el-button>
-      <el-button @click="closeModal">{{ modalOptions.cancelText }}</el-button>
-    </template>
-  </el-dialog>
+  <FormDialog
+    v-model="dialogVisible"
+    :title="dialogTitle"
+    :operationType="operationType"
+    width="30%"
+    @confirm="sendForm"
+    @close="close"
+    @cancel="close"
+  >
+    <el-form :model="form" label-width="100px" :rules="formRules" ref="formRef">
+      <el-form-item label="鏀跺叆鏃ユ湡" prop="incomeDate">
+        <el-date-picker
+          style="width: 100%"
+          v-model="form.incomeDate"
+          format="YYYY-MM-DD"
+          value-format="YYYY-MM-DD"
+          type="date"
+          placeholder="璇烽�夋嫨鏃ユ湡"
+          clearable
+        />
+      </el-form-item>
+      <el-form-item label="鏀跺叆绫诲瀷" prop="incomeType">
+        <el-select
+          v-model="form.incomeType"
+          placeholder="璇烽�夋嫨"
+          clearable
+        >
+          <el-option :label="item.label" :value="item.value" v-for="(item,index) in income_types" :key="index" />
+        </el-select>
+      </el-form-item>
+      <el-form-item label="瀹㈡埛鍚嶇О" prop="customerName">
+        <el-input v-model="form.customerName" placeholder="璇疯緭鍏�" />
+      </el-form-item>
+      <el-form-item label="鏀跺叆閲戦" prop="incomeMoney">
+        <el-input-number :step="0.01" :min="0" style="width: 100%"
+          v-model="form.incomeMoney"
+          placeholder="璇疯緭鍏�"
+        />
+      </el-form-item>
+      <el-form-item label="鏀跺叆鎻忚堪" prop="incomeDescribed">
+        <el-input v-model="form.incomeDescribed" placeholder="璇疯緭鍏�" />
+      </el-form-item>
+      <el-form-item label="鏀舵鏂瑰紡" prop="incomeMethod">
+        <el-select
+          v-model="form.incomeMethod"
+          placeholder="璇烽�夋嫨"
+          clearable
+        >
+          <el-option :label="item.label" :value="item.value" v-for="(item,index) in payment_methods" :key="index" />
+        </el-select>
+      </el-form-item>
+      <el-form-item label="鍙戠エ鍙风爜" prop="invoiceNumber">
+        <el-input v-model="form.invoiceNumber" placeholder="璇疯緭鍏�" />
+      </el-form-item>
+      <el-form-item label="澶囨敞" prop="note">
+        <el-input
+          v-model="form.note"
+          placeholder="澶囨敞"
+        />
+      </el-form-item>
+    </el-form>
+  </FormDialog>
 </template>
 
 <script setup>
-import { useModal } from "@/hooks/useModal";
-import { add, update } from "@/api/financialManagement/revenueManagement";
-import Form from "./Form.vue";
+import { add, update, getAccountIncome } from "@/api/financialManagement/revenueManagement";
 import { ElMessage } from "element-plus";
+import useFormData from "@/hooks/useFormData";
+import FormDialog from "@/components/Dialog/FormDialog.vue";
+import { ref } from "vue";
+
 const { proxy } = getCurrentInstance()
 
 defineOptions({
@@ -23,43 +78,96 @@
 
 const emits = defineEmits(["success"]);
 
-const formRef = ref();
-const {
-  id,
-  visible,
-  loading,
-  openModal,
-  modalOptions,
-  handleConfirm,
-  closeModal,
-} = useModal({ title: "鏀跺叆" });
+const formRef = ref(null);
+const dialogVisible = ref(false);
+const operationType = ref("add"); // add | edit
+const id = ref(undefined);
+const submitting = ref(false);
+
+const dialogTitle = (type) => {
+  if (type === "edit") return "缂栬緫鏀跺叆";
+  return "鏂板鏀跺叆";
+};
+
+const { income_types } = proxy.useDict("income_types");
+const { payment_methods } = proxy.useDict("payment_methods");
+
+const formRules = {
+  customerName: [{ required: true, trigger: "blur", message: "璇疯緭鍏�" }],
+  incomeMoney: [{ required: true, trigger: "blur", message: "璇疯緭鍏�" }],
+  incomeDescribed: [{ required: true, trigger: "blur", message: "璇疯緭鍏�" }],
+  incomeDate: [{ required: true, trigger: "change", message: "璇烽�夋嫨" }],
+  incomeType: [{ required: true, trigger: "change", message: "璇烽�夋嫨" }],
+  incomeMethod: [{ required: true, trigger: "change", message: "璇烽�夋嫨" }],
+}
+
+const { form, resetForm } = useFormData({
+  incomeDate: undefined, // 鏀跺叆鏃ユ湡
+  incomeType: undefined, // 鏀跺叆绫诲瀷
+  customerName: undefined, // 瀹㈡埛鍚嶇О
+  incomeMoney: undefined, // 鏀跺叆閲戦
+  incomeDescribed: undefined, // 鏀跺叆鎻忚堪
+  incomeMethod: undefined, // 鏀舵鏂瑰紡
+  invoiceNumber: undefined, // 鍙戠エ鍙风爜
+  note: undefined, // 澶囨敞
+});
 
 const sendForm = () => {
-	proxy.$refs.formRef.$refs.formRef.validate(async valid => {
-		if (valid) {
-			const {code} = id.value
-				? await update({id: id.value, ...formRef.value.form})
-				: await add(formRef.value.form);
-			if (code == 200) {
-				emits("success");
-				ElMessage({message: "鎿嶄綔鎴愬姛", type: "success"});
-				close();
-			} else {
-				loading.value = false;
-			}
-		}
-	})
+  if (submitting.value) return;
+  formRef.value?.validate(async (valid) => {
+    if (valid) {
+      submitting.value = true;
+      try {
+        const { code } = id.value
+          ? await update({ id: id.value, ...form })
+          : await add(form);
+        if (code == 200) {
+          emits("success");
+          ElMessage({ message: "鎿嶄綔鎴愬姛", type: "success" });
+          close();
+        }
+      } finally {
+        submitting.value = false;
+      }
+    }
+  })
 };
 
 const close = () => {
-	formRef.value.resetFormAndValidate();
-  closeModal();
+  resetForm();
+  formRef.value?.clearValidate();
+  id.value = undefined;
+  dialogVisible.value = false;
 };
 
-const loadForm = async (id) => {
-  openModal(id);
-  await nextTick();
-  formRef.value.loadForm(id);
+const loadForm = async (rowId) => {
+  operationType.value = "edit";
+  id.value = rowId;
+  dialogVisible.value = true;
+  if (rowId) {
+    const { code, data } = await getAccountIncome(rowId);
+    if (code == 200) {
+      form.incomeDate = data.incomeDate;
+      form.incomeType = data.incomeType;
+      form.customerName = data.customerName;
+      form.incomeMoney = data.incomeMoney;
+      form.incomeDescribed = data.incomeDescribed;
+      form.incomeMethod = data.incomeMethod;
+      form.invoiceNumber = data.invoiceNumber;
+      form.note = data.note;
+    }
+  } else {
+    resetForm();
+    formRef.value?.clearValidate();
+  }
+};
+
+const openModal = () => {
+  operationType.value = "add";
+  id.value = undefined;
+  resetForm();
+  formRef.value?.clearValidate();
+  dialogVisible.value = true;
 };
 
 defineExpose({
diff --git a/src/views/financialManagement/revenueManagement/filesDia.vue b/src/views/financialManagement/revenueManagement/filesDia.vue
deleted file mode 100644
index f752496..0000000
--- a/src/views/financialManagement/revenueManagement/filesDia.vue
+++ /dev/null
@@ -1,202 +0,0 @@
-<template>
-  <div>
-    <el-dialog
-        v-model="dialogFormVisible"
-        title="涓婁紶闄勪欢"
-        width="50%"
-        @close="closeDia"
-    >
-      <div style="margin-bottom: 10px;text-align: right">
-        <el-upload
-            v-model:file-list="fileList"
-            class="upload-demo"
-            :action="uploadUrl"
-            :on-success="handleUploadSuccess"
-            :on-error="handleUploadError"
-            name="file"
-            :show-file-list="false"
-            :headers="headers"
-            style="display: inline;margin-right: 10px"
-        >
-          <el-button type="primary">涓婁紶闄勪欢</el-button>
-        </el-upload>
-        <el-button type="danger" plain @click="handleDelete">鍒犻櫎</el-button>
-      </div>
-      <PIMTable
-          rowKey="id"
-          :column="tableColumn"
-          :tableData="tableData"
-          :tableLoading="tableLoading"
-          :isSelection="true"
-          @selection-change="handleSelectionChange"
-          height="500"
-      >
-      </PIMTable>
-			<pagination
-				style="margin: 10px 0"
-				v-show="total > 0"
-				@pagination="paginationSearch"
-				:total="total"
-				:page="page.current"
-				:limit="page.size"
-			/>
-      <template #footer>
-        <div class="dialog-footer">
-          <el-button @click="closeDia">鍙栨秷</el-button>
-        </div>
-      </template>
-    </el-dialog>
-    <filePreview ref="filePreviewRef" />
-  </div>
-</template>
-
-<script setup>
-import {ref} from "vue";
-import {ElMessageBox} from "element-plus";
-import {getToken} from "@/utils/auth.js";
-import filePreview from '@/components/filePreview/index.vue'
-import {
-  fileAdd,
-  fileDel,
-  fileListPage
-} from "@/api/financialManagement/revenueManagement.js";
-import Pagination from "@/components/PIMTable/Pagination.vue";
-const { proxy } = getCurrentInstance()
-const emit = defineEmits(['close'])
-
-const dialogFormVisible = ref(false);
-const currentId = ref('')
-const selectedRows = ref([]);
-const filePreviewRef = ref()
-const tableColumn = ref([
-  {
-    label: "鏂囦欢鍚嶇О",
-    prop: "name",
-  },
-  {
-    dataType: "action",
-    label: "鎿嶄綔",
-    align: "center",
-    operation: [
-      {
-        name: "涓嬭浇",
-        type: "text",
-        clickFun: (row) => {
-          downLoadFile(row);
-        },
-      },
-      {
-        name: "棰勮",
-        type: "text",
-        clickFun: (row) => {
-          lookFile(row);
-        },
-      }
-    ],
-  },
-]);
-const page = reactive({
-	current: 1,
-	size: 100,
-});
-const total = ref(0);
-const tableData = ref([]);
-const fileList = ref([]);
-const tableLoading = ref(false);
-const accountType = ref('')
-const headers = ref({
-  Authorization: "Bearer " + getToken(),
-});
-const uploadUrl = ref(import.meta.env.VITE_APP_BASE_API + "/file/upload"); // 涓婁紶鐨勫浘鐗囨湇鍔″櫒鍦板潃
-
-// 鎵撳紑寮规
-const openDialog = (row,type) => {
-  accountType.value = type;
-  dialogFormVisible.value = true;
-  currentId.value = row.id;
-  getList()
-}
-const paginationSearch = (obj) => {
-	page.current = obj.page;
-	page.size = obj.limit;
-	getList();
-};
-const getList = () => {
-  fileListPage({accountId: currentId.value,accountType:accountType.value, ...page}).then(res => {
-    tableData.value = res.data.records;
-		total.value = res.data.total;
-  })
-}
-// 琛ㄦ牸閫夋嫨鏁版嵁
-const handleSelectionChange = (selection) => {
-  selectedRows.value = selection;
-};
-
-// 鍏抽棴寮规
-const closeDia = () => {
-  dialogFormVisible.value = false;
-  emit('close')
-};
-// 涓婁紶鎴愬姛澶勭悊
-function handleUploadSuccess(res, file) {
-  // 濡傛灉涓婁紶鎴愬姛
-  if (res.code == 200) {
-    const fileRow = {}
-    fileRow.name = res.data.originalName
-    fileRow.url = res.data.tempPath
-    uploadFile(fileRow)
-  } else {
-    proxy.$modal.msgError("鏂囦欢涓婁紶澶辫触");
-  }
-}
-function uploadFile(file) {
-  file.accountId = currentId.value;
-  file.accountType = accountType.value;
-  fileAdd(file).then(res => {
-    proxy.$modal.msgSuccess("鏂囦欢涓婁紶鎴愬姛");
-    getList()
-  })
-}
-// 涓婁紶澶辫触澶勭悊
-function handleUploadError() {
-  proxy.$modal.msgError("鏂囦欢涓婁紶澶辫触");
-}
-// 涓嬭浇闄勪欢
-const downLoadFile = (row) => {
-  proxy.$download.name(row.url);
-}
-// 鍒犻櫎
-const handleDelete = () => {
-  let ids = [];
-  if (selectedRows.value.length > 0) {
-    ids = selectedRows.value.map((item) => item.id);
-  } else {
-    proxy.$modal.msgWarning("璇烽�夋嫨鏁版嵁");
-    return;
-  }
-  ElMessageBox.confirm("閫変腑鐨勫唴瀹瑰皢琚垹闄わ紝鏄惁纭鍒犻櫎锛�", "瀵煎嚭", {
-    confirmButtonText: "纭",
-    cancelButtonText: "鍙栨秷",
-    type: "warning",
-  }).then(() => {
-    fileDel(ids).then((res) => {
-      proxy.$modal.msgSuccess("鍒犻櫎鎴愬姛");
-      getList();
-    });
-  }).catch(() => {
-    proxy.$modal.msg("宸插彇娑�");
-  });
-};
-// 棰勮闄勪欢
-const lookFile = (row) => {
-  filePreviewRef.value.open(row.url)
-}
-
-defineExpose({
-  openDialog,
-});
-</script>
-
-<style scoped>
-
-</style>
\ No newline at end of file
diff --git a/src/views/financialManagement/revenueManagement/index.vue b/src/views/financialManagement/revenueManagement/index.vue
index 9dcd23e..47961e5 100644
--- a/src/views/financialManagement/revenueManagement/index.vue
+++ b/src/views/financialManagement/revenueManagement/index.vue
@@ -55,12 +55,12 @@
         @pagination="changePage"
       >
         <template #operation="{ row }">
-          <el-button type="primary" text @click="edit(row.id)" icon="editPen">
+          <el-button type="primary" link @click="edit(row.id)">
             缂栬緫
           </el-button>
           <el-button
             type="primary"
-            text
+						link
             @click="openFilesFormDia(row)"
           >
             闄勪欢
@@ -69,18 +69,27 @@
       </PIMTable>
     </div>
     <Modal ref="modalRef" @success="getTableData"></Modal>
-    <files-dia ref="filesDia"></files-dia>
+    <FileListDialog 
+      ref="fileListRef" 
+      v-model="fileListDialogVisible"
+      :show-upload-button="true"
+      :show-delete-button="true"
+      :upload-method="handleUpload"
+      :delete-method="handleFileDelete"
+    />
   </div>
 </template>
 
 <script setup>
 import { usePaginationApi } from "@/hooks/usePaginationApi";
-import { listPage, delAccountIncome } from "@/api/financialManagement/revenueManagement";
+import { listPage, delAccountIncome, fileListPage, fileAdd, fileDel } from "@/api/financialManagement/revenueManagement";
 import { onMounted, getCurrentInstance } from "vue";
 import Modal from "./Modal.vue";
 import { ElMessageBox, ElMessage } from "element-plus";
 import dayjs from "dayjs";
-import FilesDia from "./filesDia.vue";
+import FileListDialog from "@/components/Dialog/FileListDialog.vue";
+import request from "@/utils/request";
+import { getToken } from "@/utils/auth";
 
 defineOptions({
   name: "鏀跺叆绠$悊",
@@ -92,7 +101,10 @@
 const modalRef = ref();
 const { payment_methods } = proxy.useDict("payment_methods");
 const { income_types } = proxy.useDict("income_types");
-const filesDia = ref()
+const fileListRef = ref(null);
+const fileListDialogVisible = ref(false);
+const currentFileRow = ref(null);
+const accountType = ref('鏀跺叆');
 
 const {
   filters,
@@ -111,12 +123,10 @@
   [
     {
       label: "鏀跺叆鏃ユ湡",
-      align: "center",
       prop: "incomeDate",
     },
     {
       label: "鏀跺叆绫诲瀷",
-      align: "center",
       prop: "incomeType",
       dataType: "tag",
       formatData: (params) => {
@@ -129,26 +139,25 @@
     },
     {
       label: "瀹㈡埛鍚嶇О",
-      align: "center",
       prop: "customerName",
+			width: '200'
 
     },
     {
       label: "鏀跺叆閲戦",
-      align: "center",
       prop: "incomeMoney",
 
     },
     {
       label: "鏀跺叆鎻忚堪",
-      align: "center",
       prop: "incomeDescribed",
 
     },
     {
       label: "鏀舵鏂瑰紡",
-      align: "center",
       prop: "incomeMethod",
+			align: 'center',
+			width: '100',
       dataType: "tag",
       formatData: (params) => {
         if (payment_methods.value.find((m) => m.value == params)) {
@@ -160,24 +169,20 @@
     },
     {
       label: "鍙戠エ鍙风爜",
-      align: "center",
       prop: "invoiceNumber",
 
     },
     {
       label: "澶囨敞",
-      align: "center",
       prop: "note",
 
     },
     {
       label: "褰曞叆浜�",
-      align: "center",
       prop: "inputUser",
     },
     {
       label: "褰曞叆鏃ユ湡",
-      align: "center",
       prop: "inputTime",
 
     },
@@ -187,7 +192,7 @@
       dataType: "slot",
       slot: "operation",
       align: "center",
-      width: "200px",
+      width: "160px",
     },
   ]
 );
@@ -252,10 +257,154 @@
     });
 };
 // 鎵撳紑闄勪欢寮规
-const openFilesFormDia = (row) => {
-  nextTick(() => {
-    filesDia.value?.openDialog( row,'鏀跺叆')
-  })
+const openFilesFormDia = async (row) => {
+  currentFileRow.value = row;
+  accountType.value = '鏀跺叆';
+  try {
+    const res = await fileListPage({
+      accountId: row.id,
+      accountType: accountType.value,
+      current: 1,
+      size: 100
+    });
+    if (res.code === 200 && fileListRef.value) {
+      // 灏嗘暟鎹浆鎹负 FileListDialog 闇�瑕佺殑鏍煎紡
+      const fileList = (res.data?.records || []).map(item => ({
+        name: item.name,
+        url: item.url,
+        id: item.id,
+        ...item
+      }));
+      fileListRef.value.open(fileList);
+      fileListDialogVisible.value = true;
+    }
+  } catch (error) {
+    proxy.$modal.msgError("鑾峰彇闄勪欢鍒楄〃澶辫触");
+  }
+};
+
+// 涓婁紶闄勪欢
+const handleUpload = async () => {
+  if (!currentFileRow.value) {
+    proxy.$modal.msgWarning("璇峰厛閫夋嫨鏁版嵁");
+    return null;
+  }
+  
+  return new Promise((resolve) => {
+    // 鍒涘缓涓�涓殣钘忕殑鏂囦欢杈撳叆鍏冪礌
+    const input = document.createElement('input');
+    input.type = 'file';
+    input.style.display = 'none';
+    input.onchange = async (e) => {
+      const file = e.target.files[0];
+      if (!file) {
+        resolve(null);
+        return;
+      }
+      
+      try {
+        // 浣跨敤 FormData 涓婁紶鏂囦欢
+        const formData = new FormData();
+        formData.append('file', file);
+        
+        const uploadRes = await request({
+          url: '/file/upload',
+          method: 'post',
+          data: formData,
+          headers: {
+            'Content-Type': 'multipart/form-data',
+            Authorization: `Bearer ${getToken()}`
+          }
+        });
+        
+        if (uploadRes.code === 200) {
+          // 淇濆瓨闄勪欢淇℃伅
+          const fileData = {
+            accountId: currentFileRow.value.id,
+            accountType: accountType.value,
+            name: uploadRes.data.originalName || file.name,
+            url: uploadRes.data.tempPath || uploadRes.data.url
+          };
+          
+          const saveRes = await fileAdd(fileData);
+          if (saveRes.code === 200) {
+            proxy.$modal.msgSuccess("鏂囦欢涓婁紶鎴愬姛");
+            // 閲嶆柊鍔犺浇鏂囦欢鍒楄〃
+            const listRes = await fileListPage({
+              accountId: currentFileRow.value.id,
+              accountType: accountType.value,
+              current: 1,
+              size: 100
+            });
+            if (listRes.code === 200 && fileListRef.value) {
+              const fileList = (listRes.data?.records || []).map(item => ({
+                name: item.name,
+                url: item.url,
+                id: item.id,
+                ...item
+              }));
+              fileListRef.value.setList(fileList);
+            }
+            // 杩斿洖鏂版枃浠朵俊鎭�
+            resolve({
+              name: fileData.name,
+              url: fileData.url,
+              id: saveRes.data?.id
+            });
+          } else {
+            proxy.$modal.msgError(saveRes.msg || "鏂囦欢淇濆瓨澶辫触");
+            resolve(null);
+          }
+        } else {
+          proxy.$modal.msgError(uploadRes.msg || "鏂囦欢涓婁紶澶辫触");
+          resolve(null);
+        }
+      } catch (error) {
+        proxy.$modal.msgError("鏂囦欢涓婁紶澶辫触");
+        resolve(null);
+      } finally {
+        document.body.removeChild(input);
+      }
+    };
+    
+    document.body.appendChild(input);
+    input.click();
+  });
+};
+
+// 鍒犻櫎闄勪欢
+const handleFileDelete = async (row) => {
+  try {
+    const res = await fileDel([row.id]);
+    if (res.code === 200) {
+      proxy.$modal.msgSuccess("鍒犻櫎鎴愬姛");
+      // 閲嶆柊鍔犺浇鏂囦欢鍒楄〃
+      if (currentFileRow.value && fileListRef.value) {
+        const listRes = await fileListPage({
+          accountId: currentFileRow.value.id,
+          accountType: accountType.value,
+          current: 1,
+          size: 100
+        });
+        if (listRes.code === 200) {
+          const fileList = (listRes.data?.records || []).map(item => ({
+            name: item.name,
+            url: item.url,
+            id: item.id,
+            ...item
+          }));
+          fileListRef.value.setList(fileList);
+        }
+      }
+      return true; // 杩斿洖 true 琛ㄧず鍒犻櫎鎴愬姛锛岀粍浠朵細鏇存柊鍒楄〃
+    } else {
+      proxy.$modal.msgError(res.msg || "鍒犻櫎澶辫触");
+      return false;
+    }
+  } catch (error) {
+    proxy.$modal.msgError("鍒犻櫎澶辫触");
+    return false;
+  }
 };
 
 onMounted(() => {
diff --git a/src/views/procurementManagement/paymentEntry/index.vue b/src/views/procurementManagement/paymentEntry/index.vue
index 89152bf..5ee8d17 100644
--- a/src/views/procurementManagement/paymentEntry/index.vue
+++ b/src/views/procurementManagement/paymentEntry/index.vue
@@ -537,7 +537,7 @@
   })
     .then(() => {
       tableLoading.value = true;
-			delPaymentRegistration(row.id)
+			delPaymentRegistration([row.id])
         .then((res) => {
           proxy.$modal.msgSuccess("鍒犻櫎鎴愬姛");
           getList();
diff --git a/src/views/procurementManagement/paymentHistory/index.vue b/src/views/procurementManagement/paymentHistory/index.vue
index c38b4b0..179373b 100644
--- a/src/views/procurementManagement/paymentHistory/index.vue
+++ b/src/views/procurementManagement/paymentHistory/index.vue
@@ -43,6 +43,13 @@
           鎼滅储
         </el-button>
         <el-button @click="handleExport">瀵煎嚭</el-button>
+        <el-button
+          type="danger"
+          :disabled="selectedRows.length === 0"
+          @click="handleBatchDelete"
+        >
+          鎵归噺鍒犻櫎 ({{ selectedRows.length }})
+        </el-button>
       </el-form-item>
     </el-form>
     <div class="table_list">
@@ -58,7 +65,18 @@
         :tableLoading="tableLoading"
         @pagination="pagination"
         :total="page.total"
-      ></PIMTable>
+      >
+        <template #operation="{ row }">
+          <el-button
+            type="primary"
+            link
+            size="small"
+            @click="handleDelete(row)"
+          >
+            鍒犻櫎
+          </el-button>
+        </template>
+      </PIMTable>
     </div>
   </div>
 </template>
@@ -66,7 +84,9 @@
 <script setup>
 import { ref, reactive, getCurrentInstance, onMounted } from "vue";
 import { Search } from "@element-plus/icons-vue";
-import { paymentHistoryListPage } from "@/api/procurementManagement/paymentEntry.js";
+import { ElMessageBox } from "element-plus";
+import { paymentHistoryListPage} from "@/api/procurementManagement/paymentEntry.js";
+import {delPaymentRegistration } from "@/api/procurementManagement/procurementInvoiceLedger.js";
 import useFormData from "@/hooks/useFormData";
 import dayjs from "dayjs";
 
@@ -104,6 +124,13 @@
   {
     label: "鐧昏鏃ユ湡",
     prop: "registrationtDate",
+  },
+  {
+    label: "鎿嶄綔",
+    dataType: "slot",
+    slot: "operation",
+    width: 100,
+    align: "center",
   },
 ]);
 const tableData = ref([]);
@@ -170,6 +197,62 @@
   getList();
 };
 
+// 鍒犻櫎
+const handleDelete = (row) => {
+  ElMessageBox.confirm("閫変腑鐨勫唴瀹瑰皢琚垹闄わ紝鏄惁纭鍒犻櫎锛�", "鍒犻櫎鎻愮ず", {
+    confirmButtonText: "纭",
+    cancelButtonText: "鍙栨秷",
+    type: "warning",
+  })
+    .then(() => {
+      tableLoading.value = true;
+      delPaymentRegistration([row.id])
+        .then((res) => {
+          proxy.$modal.msgSuccess("鍒犻櫎鎴愬姛");
+          getList();
+        })
+        .finally(() => {
+          tableLoading.value = false;
+        });
+    })
+    .catch(() => {
+      proxy.$modal.msg("宸插彇娑�");
+    });
+};
+
+// 鎵归噺鍒犻櫎
+const handleBatchDelete = () => {
+  if (selectedRows.value.length === 0) {
+    proxy.$modal.msgWarning("璇烽�夋嫨瑕佸垹闄ょ殑鏁版嵁");
+    return;
+  }
+  ElMessageBox.confirm(
+    `纭畾瑕佸垹闄ら�変腑鐨� ${selectedRows.value.length} 鏉℃暟鎹悧锛焋,
+    "鍒犻櫎鎻愮ず",
+    {
+      confirmButtonText: "纭",
+      cancelButtonText: "鍙栨秷",
+      type: "warning",
+    }
+  )
+    .then(() => {
+      tableLoading.value = true;
+      const ids = selectedRows.value.map((item) => item.id);
+      delPaymentRegistration(ids)
+        .then((res) => {
+          proxy.$modal.msgSuccess("鍒犻櫎鎴愬姛");
+          selectedRows.value = [];
+          getList();
+        })
+        .finally(() => {
+          tableLoading.value = false;
+        });
+    })
+    .catch(() => {
+      proxy.$modal.msg("宸插彇娑�");
+    });
+};
+
 // 瀵煎嚭
 const handleExport = () => {
   const { paymentDate, ...rest } = searchForm;
diff --git a/src/views/salesManagement/receiptPaymentHistory/index.vue b/src/views/salesManagement/receiptPaymentHistory/index.vue
index 7bcb433..f66bed7 100644
--- a/src/views/salesManagement/receiptPaymentHistory/index.vue
+++ b/src/views/salesManagement/receiptPaymentHistory/index.vue
@@ -27,6 +27,13 @@
       <el-form-item>
         <el-button type="primary" @click="handleQuery"> 鎼滅储 </el-button>
         <el-button @click="handleExport">瀵煎嚭</el-button>
+        <el-button
+          type="danger"
+          :disabled="selectedRows.length === 0"
+          @click="handleBatchDelete"
+        >
+          鎵归噺鍒犻櫎 ({{ selectedRows.length }})
+        </el-button>
       </el-form-item>
     </el-form>
     <div class="table_list">
@@ -42,7 +49,18 @@
         :total="page.total"
         @pagination="pagination"
         @selection-change="handleSelectionChange"
-      ></PIMTable>
+      >
+        <template #operation="{ row }">
+          <el-button
+            type="primary"
+            link
+            size="small"
+            @click="handleDelete(row)"
+          >
+            鍒犻櫎
+          </el-button>
+        </template>
+      </PIMTable>
     </div>
   </div>
 </template>
@@ -50,7 +68,8 @@
 <script setup>
 import { ref, reactive, getCurrentInstance, onMounted } from "vue";
 import { Search } from "@element-plus/icons-vue";
-import { receiptPaymentHistoryListPage } from "@/api/salesManagement/receiptPayment.js";
+import { ElMessageBox } from "element-plus";
+import { receiptPaymentHistoryListPage, receiptPaymentDel } from "@/api/salesManagement/receiptPayment.js";
 import useFormData from "@/hooks/useFormData";
 import dayjs from "dayjs";
 
@@ -104,6 +123,14 @@
     label: "鐧昏鏃ユ湡",
     prop: "createTime",
     width:100
+  },
+  {
+    label: "鎿嶄綔",
+    dataType: "slot",
+    fixed: "right",
+    slot: "operation",
+    width: 100,
+    align: "center",
   },
 ]);
 const tableData = ref([]);
@@ -175,6 +202,66 @@
   getList();
 };
 
+// 鍒犻櫎
+const handleDelete = (row) => {
+  ElMessageBox.confirm("纭鍒犻櫎璇ヨ褰曞悧锛�", "鎻愮ず", {
+    confirmButtonText: "纭畾",
+    cancelButtonText: "鍙栨秷",
+    type: "warning",
+  })
+    .then(async () => {
+      try {
+        tableLoading.value = true;
+        await receiptPaymentDel([row.id]);
+        proxy.$modal.msgSuccess("鍒犻櫎鎴愬姛");
+        getList();
+      } catch (error) {
+        console.error("鍒犻櫎澶辫触:", error);
+        proxy.$modal.msgError("鍒犻櫎澶辫触");
+      } finally {
+        tableLoading.value = false;
+      }
+    })
+    .catch(() => {
+      proxy.$modal.msg("宸插彇娑堝垹闄�");
+    });
+};
+
+// 鎵归噺鍒犻櫎
+const handleBatchDelete = () => {
+  if (selectedRows.value.length === 0) {
+    proxy.$modal.msgWarning("璇烽�夋嫨瑕佸垹闄ょ殑鏁版嵁");
+    return;
+  }
+  ElMessageBox.confirm(
+    `纭畾瑕佸垹闄ら�変腑鐨� ${selectedRows.value.length} 鏉℃暟鎹悧锛焋,
+    "鍒犻櫎鎻愮ず",
+    {
+      confirmButtonText: "纭",
+      cancelButtonText: "鍙栨秷",
+      type: "warning",
+    }
+  )
+    .then(async () => {
+      try {
+        tableLoading.value = true;
+        const ids = selectedRows.value.map((item) => item.id);
+        await receiptPaymentDel(ids);
+        proxy.$modal.msgSuccess("鍒犻櫎鎴愬姛");
+        selectedRows.value = [];
+        getList();
+      } catch (error) {
+        console.error("鍒犻櫎澶辫触:", error);
+        proxy.$modal.msgError("鍒犻櫎澶辫触");
+      } finally {
+        tableLoading.value = false;
+      }
+    })
+    .catch(() => {
+      proxy.$modal.msg("宸插彇娑�");
+    });
+};
+
 // 瀵煎嚭
 const handleExport = () => {
   const { receiptPaymentDate, ...rest } = searchForm;

--
Gitblit v1.9.3