进销存-升级
1.修改上传组件bug
2.付款流水和回款流水添加删除功能
3.调整财务管理页面样式和运用组件
已修改10个文件
已删除3个文件
1408 ■■■■■ 文件已修改
src/components/Dialog/FileListDialog.vue 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/PIMTable/PIMTable.vue 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/financialManagement/expenseManagement/Form.vue 123 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/financialManagement/expenseManagement/Modal.vue 192 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/financialManagement/expenseManagement/index.vue 187 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/financialManagement/loanManagement/index.vue 9 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/financialManagement/revenueManagement/Form.vue 123 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/financialManagement/revenueManagement/Modal.vue 192 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/financialManagement/revenueManagement/filesDia.vue 202 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/financialManagement/revenueManagement/index.vue 191 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/procurementManagement/paymentEntry/index.vue 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/procurementManagement/paymentHistory/index.vue 87 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/salesManagement/receiptPaymentHistory/index.vue 91 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/Dialog/FileListDialog.vue
@@ -229,10 +229,9 @@
const handleUpload = async () => {
  if (props.uploadMethod) {
    const newItem = await props.uploadMethod()
    if (newItem) {
      addAttachment(newItem)
    }
    // å¦‚果提供了自定义上传方法,由父组件负责更新列表(通过 setList)
    // è¿™é‡Œä¸å†è‡ªåŠ¨æ·»åŠ ï¼Œé¿å…ä¸Žçˆ¶ç»„ä»¶çš„ setList é‡å¤
    await props.uploadMethod()
  }
  emit('upload')
}
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"
src/views/financialManagement/expenseManagement/Form.vue
ÎļþÒÑɾ³ý
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({
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(() => {
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 "待还款";
src/views/financialManagement/revenueManagement/Form.vue
ÎļþÒÑɾ³ý
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({
src/views/financialManagement/revenueManagement/filesDia.vue
ÎļþÒÑɾ³ý
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(() => {
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();
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;
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;