maven
2025-08-07 c1afd811abb7879a2b7359e419ce99d52235ded9
Merge remote-tracking branch 'origin/dev_7004' into dev_7004
已修改4个文件
已添加11个文件
1660 ■■■■■ 文件已修改
package.json 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/financialManagement/expenseManagement.js 78 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/financialManagement/revenueManagement.js 78 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/styles/element-ui.scss 14 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/filePreview/index.vue 202 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main.js 129 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/financialManagement/expenseManagement/Form.vue 123 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/financialManagement/expenseManagement/Modal.vue 69 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/financialManagement/expenseManagement/index.vue 279 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/financialManagement/financialStatements/index.vue 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/financialManagement/revenueManagement/Form.vue 123 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/financialManagement/revenueManagement/Modal.vue 69 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/financialManagement/revenueManagement/filesDia.vue 202 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/financialManagement/revenueManagement/index.vue 279 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/salesManagement/salesLedger/fileList.vue 9 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
package.json
@@ -17,6 +17,8 @@
  },
  "dependencies": {
    "@element-plus/icons-vue": "2.3.1",
    "@vue-office/docx": "^1.6.3",
    "@vue-office/excel": "^1.7.14",
    "@vueup/vue-quill": "1.2.0",
    "@vueuse/core": "10.11.0",
    "axios": "0.28.1",
src/api/financialManagement/expenseManagement.js
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,78 @@
import request from "@/utils/request";
// æŸ¥è¯¢åˆ—表
export const listPage = (params) => {
  return request({
    url: "/account/accountExpense/listPage",
    method: "get",
    params,
  });
};
// æ–°å¢ž
export function add(data) {
  return request({
    url: "/account/accountExpense/add",
    method: "post",
    data: data,
  });
}
// ç¼–辑
export function update(data) {
  return request({
    url: "/account/accountExpense/update",
    method: "post",
    data: data,
  });
}
//导出
export const exportAccountExpense = (query) => {
  return request({
    url: "/account/accountExpense/export",
    method: "post",
    data: query,
    responseType: "blob",
  });
};
export const delAccountExpense = (query) => {
  return request({
    url: `account/accountExpense/del`,
    method: "delete",
    data: query,
  });
};
export const getAccountExpense = (id) => {
  return request({
    url: `/account/accountExpense/${id}`,
    method: "get",
  });
};
// æŸ¥è¯¢é™„件列表
export function fileListPage(query) {
  return request({
    url: "/account/accountFile/listPage",
    method: "get",
    params: query,
  });
}
// ä¿å­˜é™„件列表
export function fileAdd(query) {
  return request({
    url: "/account/accountFile/add",
    method: "post",
    data: query,
  });
}
// åˆ é™¤é™„件列表
export function fileDel(query) {
  return request({
    url: "/account/accountFile/del",
    method: "delete",
    data: query,
  });
}
src/api/financialManagement/revenueManagement.js
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,78 @@
import request from "@/utils/request";
// æŸ¥è¯¢åˆ—表
export const listPage = (params) => {
  return request({
    url: "/account/accountIncome/listPage",
    method: "get",
    params,
  });
};
// æ–°å¢ž
export function add(data) {
  return request({
    url: "/account/accountIncome/add",
    method: "post",
    data: data,
  });
}
// ç¼–辑
export function update(data) {
  return request({
    url: "/account/accountIncome/update",
    method: "post",
    data: data,
  });
}
//导出
export const exportAccountIncome = (query) => {
  return request({
    url: "/account/accountIncome/export",
    method: "post",
    data: query,
    responseType: "blob",
  });
};
export const delAccountIncome = (query) => {
  return request({
    url: `account/accountIncome/del`,
    method: "delete",
    data: query,
  });
};
export const getAccountIncome = (id) => {
  return request({
    url: `/account/accountIncome/${id}`,
    method: "get",
  });
};
// æŸ¥è¯¢é™„件列表
export function fileListPage(query) {
  return request({
    url: "/account/accountFile/listPage",
    method: "get",
    params: query,
  });
}
// ä¿å­˜é™„件列表
export function fileAdd(query) {
  return request({
    url: "/account/accountFile/add",
    method: "post",
    data: query,
  });
}
// åˆ é™¤é™„件列表
export function fileDel(query) {
  return request({
    url: "/account/accountFile/del",
    method: "delete",
    data: query,
  });
}
src/assets/styles/element-ui.scss
@@ -56,18 +56,18 @@
  padding: 0 !important;
}
.el-dialog__header {
  background: #F5F6F7;
  background: #f5f6f7;
  padding: 12px 16px;
  border-radius: 8px 8px 0 0;
}
.el-dialog__title {
  font-weight: 400;
  font-size: 16px;
  color: #2E3033;
  color: #2e3033;
}
.el-dialog__body {
  padding: 16px 40px 0 40px;
  max-height: 680px;
  max-height: 90vh;
  overflow-y: auto;
}
.el-dialog__footer {
@@ -79,14 +79,14 @@
  border-radius: 8px;
}
.el-message-box__header {
  background: #F5F6F7;
  background: #f5f6f7;
  padding: 12px 16px;
  border-radius: 8px 8px 0 0;
}
.el-message-box__title {
  font-weight: 400;
  font-size: 16px;
  color: #2E3033;
  color: #2e3033;
}
.el-message-box__content {
  padding: 16px 40px 0 40px;
@@ -108,7 +108,7 @@
.el-table__expanded-cell {
  padding: 0 !important;
  .el-table__header-wrapper {
    background-color: #F5F8FF !important;
    background-color: #f5f8ff !important;
  }
}
@@ -127,7 +127,7 @@
// dropdown
.el-dropdown-menu {
  a {
    display: block
    display: block;
  }
}
src/components/filePreview/index.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,202 @@
<template>
  <el-dialog v-model="dialogVisible" title="预览" width="100%" fullscreen align-center :before-close="handleClose" append-to-body>
    <div>
      <!-- å›¾ç‰‡é¢„览 -->
      <div v-if="isImage">
        <img :src="imgUrl" alt="Image Preview" />
      </div>
      <!-- PDF预览提示 -->
      <div v-if="isPdf" style="height: 100vh; display: flex; align-items: center; justify-content: center;">
        <p>正在准备PDF预览...</p>
      </div>
      <!-- Word文档预览 -->
      <div v-if="isDoc">
        <p v-if="!isDocShow">文档无法直接预览,请下载查看。</p>
        <a :href="fileUrl" v-if="!isDocShow">下载文件</a>
        <vue-office-docx
          v-else
          :src="fileUrl"
          style="height: 100vh;"
          @rendered="renderedHandler"
          @error="errorHandler"
        />
      </div>
      <!-- Excel文档预览 -->
      <div v-if="isXls">
        <p v-if="!isDocShow">文档无法直接预览,请下载查看。</p>
        <a :href="fileUrl" v-if="!isDocShow">下载文件</a>
        <vue-office-excel
          v-else
          :src="fileUrl"
          :options="options"
          style="height: 100vh;"
          @rendered="renderedHandler"
          @error="errorHandler"
        />
      </div>
      <!-- åŽ‹ç¼©æ–‡ä»¶å¤„ç† -->
      <div v-if="isZipOrRar">
        <p>压缩文件无法直接预览,请下载查看。</p>
        <a :href="fileUrl">下载文件</a>
      </div>
      <!-- ä¸æ”¯æŒçš„æ ¼å¼ -->
      <div v-if="!isSupported">
        <p>不支持的文件格式</p>
      </div>
    </div>
  </el-dialog>
</template>
<script setup>
import { ref, computed, getCurrentInstance, watch } from 'vue';
import VueOfficeDocx from '@vue-office/docx';
import '@vue-office/docx/lib/index.css';
import VueOfficeExcel from '@vue-office/excel';
import '@vue-office/excel/lib/index.css';
// å“åº”式变量
const fileUrl = ref('')
const dialogVisible = ref(false)
const { proxy } = getCurrentInstance();
const javaApi = proxy.javaApi;
// æ–‡æ¡£é¢„览状态
const isDocShow = ref(true);
const imgUrl = ref('');
const options = ref({
  xls: false,
  minColLength: 0,
  minRowLength: 0,
  widthOffset: 10,
  heightOffset: 10,
  beforeTransformData: (workbookData) => workbookData,
  transformData: (workbookData) => workbookData,
});
// è®¡ç®—属性 - åˆ¤æ–­æ–‡ä»¶ç±»åž‹
const isImage = computed(() => {
  const state = /\.(jpg|jpeg|png|gif)$/i.test(fileUrl.value);
  if (state) {
    imgUrl.value = fileUrl.value.replaceAll('word', 'img');
  }
  return state;
});
const isPdf = computed(() => {
  console.log(fileUrl.value)
  return /\.pdf$/i.test(fileUrl.value);
});
const isDoc = computed(() => {
  return /\.(doc|docx)$/i.test(fileUrl.value);
});
const isXls = computed(() => {
  const state = /\.(xls|xlsx)$/i.test(fileUrl.value);
  if (state) {
    options.value.xls = /\.(xls)$/i.test(fileUrl.value);
  }
  return state;
});
const isZipOrRar = computed(() => {
  return /\.(zip|rar)$/i.test(fileUrl.value);
});
const isSupported = computed(() => {
  return isImage.value || isPdf.value || isDoc.value || isXls.value || isZipOrRar.value;
});
// åŠ¨æ€åˆ›å»ºa标签并跳转预览PDF
const previewPdf = (url) => {
  // åˆ›å»ºa标签
  const link = document.createElement('a');
  // è®¾ç½®PDF文件URL
  link.href = url;
  // åœ¨æ–°æ ‡ç­¾é¡µæ‰“å¼€
  link.target = '_blank';
  // å®‰å…¨å±žæ€§ï¼Œé˜²æ­¢æ–°é¡µé¢è®¿é—®åŽŸé¡µé¢
  link.rel = 'noopener noreferrer';
  // å¯é€‰ï¼šè®¾ç½®é“¾æŽ¥æ–‡æœ¬
  link.textContent = '预览PDF';
  // å°†a标签添加到页面(部分浏览器要求必须在DOM中)
  document.body.appendChild(link);
  // è§¦å‘点击事件
  link.click();
  // ç§»é™¤a标签,清理DOM
  document.body.removeChild(link);
};
// ç›‘听PDF状态变化,自动触发跳转
watch(
  () => isPdf.value,
  (newVal) => {
    // å½“确认是PDF且文件URL有效时
    if (newVal && fileUrl.value) {
      // å…³é—­å¯¹è¯æ¡†
      dialogVisible.value = false;
      // åŠ ä¸ªå°å»¶è¿Ÿç¡®ä¿çŠ¶æ€æ›´æ–°å®Œæˆ
      setTimeout(() => {
        previewPdf(fileUrl.value);
        fileUrl.value = '';
      }, 100);
    }
  }
);
// æ–¹æ³•定义
const renderedHandler = () => {
  console.log("渲染完成");
  isDocShow.value = true;
  resetStyle();
};
const errorHandler = () => {
  console.log("渲染失败");
  isDocShow.value = false;
};
const open = (url) => {
  fileUrl.value = window.location.protocol+'//'+window.location.host+ url;
  dialogVisible.value = true;
};
const handleClose = () => {
  dialogVisible.value = false;
};
const resetStyle = () => {
  const elements = document.querySelectorAll('[style*="pt"]');
  for (const element of elements) {
    const style = element.getAttribute('style');
    if (style) {
      element.setAttribute('style', style.replace(/pt/g, 'px'));
    }
  }
};
// æš´éœ²open方法供外部调用
defineExpose({
  open
})
</script>
<style scoped>
img {
  max-width: 100%;
  display: block;
  margin: 0 auto;
}
.oneLine {
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
}
</style>
src/main.js
@@ -1,68 +1,81 @@
import { createApp } from 'vue'
import { createApp } from "vue";
import Cookies from 'js-cookie'
import Cookies from "js-cookie";
import ElementPlus from 'element-plus'
import 'element-plus/dist/index.css'
import 'element-plus/theme-chalk/dark/css-vars.css'
import locale from 'element-plus/es/locale/lang/zh-cn'
import ElementPlus from "element-plus";
import "element-plus/dist/index.css";
import "element-plus/theme-chalk/dark/css-vars.css";
import locale from "element-plus/es/locale/lang/zh-cn";
import '@/assets/styles/index.scss' // global css
import "@/assets/styles/index.scss"; // global css
import App from './App'
import store from './store'
import router from './router'
import directive from './directive' // directive
import App from "./App";
import store from "./store";
import router from "./router";
import directive from "./directive"; // directive
// æ³¨å†ŒæŒ‡ä»¤
import plugins from './plugins' // plugins
import { download } from '@/utils/request'
import plugins from "./plugins"; // plugins
import { download } from "@/utils/request";
// svg图标
import 'virtual:svg-icons-register'
import SvgIcon from '@/components/SvgIcon'
import elementIcons from '@/components/SvgIcon/svgicon'
import "virtual:svg-icons-register";
import SvgIcon from "@/components/SvgIcon";
import elementIcons from "@/components/SvgIcon/svgicon";
import './permission' // permission control
import "./permission"; // permission control
import { useDict } from '@/utils/dict'
import { parseTime, resetForm, addDateRange, handleTree, selectDictLabel, selectDictLabels } from '@/utils/ruoyi'
import { useDict } from "@/utils/dict";
import {
  parseTime,
  resetForm,
  addDateRange,
  handleTree,
  selectDictLabel,
  selectDictLabels,
} from "@/utils/ruoyi";
// åˆ†é¡µç»„ä»¶
import Pagination from '@/components/Pagination'
import Pagination from "@/components/Pagination";
// è‡ªå®šä¹‰è¡¨æ ¼å·¥å…·ç»„ä»¶
import RightToolbar from '@/components/RightToolbar'
import RightToolbar from "@/components/RightToolbar";
// å¯Œæ–‡æœ¬ç»„ä»¶
import Editor from "@/components/Editor"
import Editor from "@/components/Editor";
// æ–‡ä»¶ä¸Šä¼ ç»„ä»¶
import FileUpload from "@/components/FileUpload"
import FileUpload from "@/components/FileUpload";
// å›¾ç‰‡ä¸Šä¼ ç»„ä»¶
import ImageUpload from "@/components/ImageUpload"
import ImageUpload from "@/components/ImageUpload";
// å›¾ç‰‡é¢„览组件
import ImagePreview from "@/components/ImagePreview"
import ImagePreview from "@/components/ImagePreview";
// å­—典标签组件
import DictTag from '@/components/DictTag'
import DictTag from "@/components/DictTag";
// è¡¨æ ¼ç»„ä»¶
import PIMTable from "@/components/PIMTable/PIMTable.vue";
import { getToken } from "@/utils/auth";
import {calculateTaxExclusiveTotalPrice, summarizeTable,calculateTaxIncludeTotalPrice} from "@/utils/summarizeTable.js";
import {
  calculateTaxExclusiveTotalPrice,
  summarizeTable,
  calculateTaxIncludeTotalPrice,
} from "@/utils/summarizeTable.js";
const app = createApp(App)
const app = createApp(App);
// å…¨å±€æ–¹æ³•挂载
app.config.globalProperties.useDict = useDict
app.config.globalProperties.download = download
app.config.globalProperties.parseTime = parseTime
app.config.globalProperties.resetForm = resetForm
app.config.globalProperties.summarizeTable = summarizeTable
app.config.globalProperties.calculateTaxExclusiveTotalPrice = calculateTaxExclusiveTotalPrice
app.config.globalProperties.calculateTaxIncludeTotalPrice = calculateTaxIncludeTotalPrice
app.config.globalProperties.handleTree = handleTree
app.config.globalProperties.addDateRange = addDateRange
app.config.globalProperties.selectDictLabel = selectDictLabel
app.config.globalProperties.selectDictLabels = selectDictLabels
app.config.globalProperties.javaApi = 'http://114.132.189.42:8078'
app.config.globalProperties.useDict = useDict;
app.config.globalProperties.download = download;
app.config.globalProperties.parseTime = parseTime;
app.config.globalProperties.resetForm = resetForm;
app.config.globalProperties.summarizeTable = summarizeTable;
app.config.globalProperties.calculateTaxExclusiveTotalPrice =
  calculateTaxExclusiveTotalPrice;
app.config.globalProperties.calculateTaxIncludeTotalPrice =
  calculateTaxIncludeTotalPrice;
app.config.globalProperties.handleTree = handleTree;
app.config.globalProperties.addDateRange = addDateRange;
app.config.globalProperties.selectDictLabel = selectDictLabel;
app.config.globalProperties.selectDictLabels = selectDictLabels;
app.config.globalProperties.javaApi = "http://114.132.189.42:8099";
app.config.globalProperties.HaveJson = (val) => {
  return JSON.parse(JSON.stringify(val));
};
@@ -71,29 +84,29 @@
};
// å…¨å±€ç»„件挂载
app.component('DictTag', DictTag)
app.component('Pagination', Pagination)
app.component('FileUpload', FileUpload)
app.component('ImageUpload', ImageUpload)
app.component('ImagePreview', ImagePreview)
app.component('RightToolbar', RightToolbar)
app.component('Editor', Editor)
app.component('PIMTable', PIMTable)
app.component("DictTag", DictTag);
app.component("Pagination", Pagination);
app.component("FileUpload", FileUpload);
app.component("ImageUpload", ImageUpload);
app.component("ImagePreview", ImagePreview);
app.component("RightToolbar", RightToolbar);
app.component("Editor", Editor);
app.component("PIMTable", PIMTable);
app.use(router)
app.use(store)
app.use(plugins)
app.use(elementIcons)
app.component('svg-icon', SvgIcon)
app.use(router);
app.use(store);
app.use(plugins);
app.use(elementIcons);
app.component("svg-icon", SvgIcon);
directive(app)
directive(app);
// ä½¿ç”¨element-plus å¹¶ä¸”设置全局的大小
app.use(ElementPlus, {
  locale: locale,
  // æ”¯æŒ large、default、small
  size: Cookies.get('size') || 'default'
})
app._context.components.ElDialog.props.closeOnClickModal.default = false
  size: Cookies.get("size") || "default",
});
app._context.components.ElDialog.props.closeOnClickModal.default = false;
app.mount('#app')
app.mount("#app");
src/views/financialManagement/expenseManagement/Form.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,123 @@
<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>
src/views/financialManagement/expenseManagement/Modal.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,69 @@
<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>
</template>
<script setup>
import { useModal } from "@/hooks/useModal";
import { add, update } from "@/api/financialManagement/expenseManagement";
import Form from "./Form.vue";
import { ElMessage } from "element-plus";
const { proxy } = getCurrentInstance()
defineOptions({
  name: "支出新增编辑",
});
const emits = defineEmits(["success"]);
const formRef = ref();
const {
  id,
  visible,
  loading,
  openModal,
  modalOptions,
  handleConfirm,
  closeModal,
} = useModal({ title: "支出" });
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;
            }
        }
    })
};
const close = () => {
    formRef.value.resetFormAndValidate();
  closeModal();
};
const loadForm = async (id) => {
  openModal(id);
  await nextTick();
  formRef.value.loadForm(id);
};
defineExpose({
  openModal,
  loadForm,
});
</script>
src/views/financialManagement/expenseManagement/index.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,279 @@
<template>
  <div class="app-container">
    <el-form :model="filters" :inline="true">
      <el-form-item label="录入日期:">
        <el-date-picker v-model="filters.entryDate" value-format="YYYY-MM-DD" format="YYYY-MM-DD" type="daterange"
                        placeholder="请选择" clearable @change="changeDaterange" />
      </el-form-item>
      <el-form-item label="付款方式:">
        <el-select
                v-model="filters.expenseMethod"
                placeholder="请选择"
                clearable
                style="width: 200px;"
              >
                <el-option
                  v-for="item in checkout_payment"
                  :key="item.value"
                  :label="item.label"
                  :value="item.value"
                />
              </el-select>
      </el-form-item>
      <el-form-item>
        <el-button type="primary" @click="getTableData">搜索</el-button>
        <el-button @click="resetFilters">重置</el-button>
      </el-form-item>
    </el-form>
    <div class="table_list">
      <div class="actions">
        <div></div>
        <div>
          <el-button type="primary" @click="add" icon="Plus"> æ–°å¢ž </el-button>
          <el-button @click="handleOut" icon="download">导出</el-button>
          <el-button
            type="danger"
            icon="Delete"
            :disabled="multipleList.length <= 0"
            @click="deleteRow(multipleList.map((item) => item.id))"
          >
            æ‰¹é‡åˆ é™¤
          </el-button>
        </div>
      </div>
      <PIMTable
        rowKey="id"
        isSelection
        :column="columns"
        :tableData="dataList"
        :page="{
          current: pagination.currentPage,
          size: pagination.pageSize,
          total: pagination.total,
        }"
        @selection-change="handleSelectionChange"
        @pagination="changePage"
      >
        <template #operation="{ row }">
          <el-button type="primary" text @click="edit(row.id)" icon="editPen">
            ç¼–辑
          </el-button>
          <el-button
            type="primary"
            text
            @click="openFilesFormDia(row)"
          >
            é™„ä»¶
          </el-button>
        </template>
      </PIMTable>
    </div>
    <Modal ref="modalRef" @success="getTableData"></Modal>
    <files-dia ref="filesDia" @close="handleQuery"></files-dia>
  </div>
</template>
<script setup>
import { usePaginationApi } from "@/hooks/usePaginationApi";
import { listPage, delAccountExpense } 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";
defineOptions({
  name: "支出管理",
});
// è¡¨æ ¼å¤šé€‰æ¡†é€‰ä¸­é¡¹
const multipleList = ref([]);
const { proxy } = getCurrentInstance();
const modalRef = ref();
const { checkout_payment } = proxy.useDict("checkout_payment");
const { expense_types } = proxy.useDict("expense_types");
const filesDia = ref()
const {
  filters,
  columns,
  dataList,
  pagination,
  getTableData,
  resetFilters,
  onCurrentChange,
} = usePaginationApi(
  listPage,
  {
    expenseMethod: undefined,
  },
  [
    {
      label: "支出日期",
      align: "center",
      prop: "expenseDate",
    },
    {
      label: "支出类型",
      align: "center",
      prop: "expenseType",
      dataType: "tag",
      formatData: (params) => {
        if (expense_types.value.find((m) => m.value == params)) {
          return expense_types.value.find((m) => m.value == params).label;
        } else {
          return null
        }
      },
    },
    {
      label: "供应商名称",
      align: "center",
      prop: "supplierName",
    },
    {
      label: "支出金额",
      align: "center",
      prop: "expenseMoney",
    },
    {
      label: "支出描述",
      align: "center",
      prop: "expenseDescribed",
    },
    {
      label: "付款方式",
      align: "center",
      prop: "expenseMethod",
      dataType: "tag",
      formatData: (params) => {
        if (checkout_payment.value.find((m) => m.value == params)) {
          return checkout_payment.value.find((m) => m.value == params).label;
        } else {
          return null
        }
      },
    },
    {
      label: "发票号码",
      align: "center",
      prop: "invoiceNumber",
    },
    {
      label: "备注",
      align: "center",
      prop: "note",
    },
    {
      label: "录入人",
      align: "center",
      prop: "inputUser",
    },
    {
      label: "录入日期",
      align: "center",
      prop: "inputTime",
    },
    {
      fixed: "right",
      label: "操作",
      dataType: "slot",
      slot: "operation",
      align: "center",
      width: "200px",
    },
  ]
);
// å¤šé€‰åŽåšä»€ä¹ˆ
const handleSelectionChange = (selectionList) => {
  multipleList.value = selectionList;
};
const add = () => {
  modalRef.value.openModal();
};
const edit = (id) => {
  modalRef.value.loadForm(id);
};
const changePage = ({ page, limit }) => {
  pagination.currentPage = page;
    pagination.pageSize = limit;
  onCurrentChange(page);
};
const deleteRow = (id) => {
  ElMessageBox.confirm("此操作将永久删除该数据, æ˜¯å¦ç»§ç»­?", "提示", {
    confirmButtonText: "确定",
    cancelButtonText: "取消",
    type: "warning",
  }).then(async () => {
    const { code } = await delAccountExpense(id);
    if (code == 200) {
      ElMessage({
        type: "success",
        message: "删除成功",
      });
      getTableData();
    }
  });
};
const changeDaterange = (value) => {
  if (value) {
    filters.entryDateStart = dayjs(value[0]).format("YYYY-MM-DD");
    filters.entryDateEnd = dayjs(value[1]).format("YYYY-MM-DD");
  } else {
    filters.entryDateStart = undefined;
    filters.entryDateEnd = undefined;
  }
  getTableData();
};
const handleOut = () => {
  ElMessageBox.confirm("选中的内容将被导出,是否确认导出?", "导出", {
    confirmButtonText: "确认",
    cancelButtonText: "取消",
    type: "warning",
  })
    .then(() => {
      proxy.download(`/account/accountExpense/export`, {}, "支出台账.xlsx");
    })
    .catch(() => {
      proxy.$modal.msg("已取消");
    });
};
// æ‰“开附件弹框
const openFilesFormDia = (row) => {
  nextTick(() => {
    filesDia.value?.openDialog( row,'支出')
  })
};
onMounted(() => {
  filters.entryDate = [
    dayjs().format("YYYY-MM-DD"),
    dayjs().add(1, "day").format("YYYY-MM-DD"),
  ]
  filters.entryDateStart = dayjs().format("YYYY-MM-DD")
  filters.entryDateEnd = dayjs().add(1, "day").format("YYYY-MM-DD")
  getTableData();
});
</script>
<style lang="scss" scoped>
.table_list {
  margin-top: unset;
}
.actions {
  display: flex;
  justify-content: space-between;
  margin-bottom: 10px;
}
</style>
src/views/financialManagement/financialStatements/index.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,4 @@
<template>
</template>
<script setup>
</script>
src/views/financialManagement/revenueManagement/Form.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,123 @@
<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>
src/views/financialManagement/revenueManagement/Modal.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,69 @@
<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>
</template>
<script setup>
import { useModal } from "@/hooks/useModal";
import { add, update } from "@/api/financialManagement/revenueManagement";
import Form from "./Form.vue";
import { ElMessage } from "element-plus";
const { proxy } = getCurrentInstance()
defineOptions({
  name: "收入新增编辑",
});
const emits = defineEmits(["success"]);
const formRef = ref();
const {
  id,
  visible,
  loading,
  openModal,
  modalOptions,
  handleConfirm,
  closeModal,
} = useModal({ title: "收入" });
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;
            }
        }
    })
};
const close = () => {
    formRef.value.resetFormAndValidate();
  closeModal();
};
const loadForm = async (id) => {
  openModal(id);
  await nextTick();
  formRef.value.loadForm(id);
};
defineExpose({
  openModal,
  loadForm,
});
</script>
src/views/financialManagement/revenueManagement/filesDia.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,202 @@
<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>
src/views/financialManagement/revenueManagement/index.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,279 @@
<template>
  <div class="app-container">
    <el-form :model="filters" :inline="true">
      <el-form-item label="录入日期:">
        <el-date-picker v-model="filters.entryDate" value-format="YYYY-MM-DD" format="YYYY-MM-DD" type="daterange"
                        placeholder="请选择" clearable @change="changeDaterange" />
      </el-form-item>
      <el-form-item label="收款方式:">
        <el-select
                v-model="filters.incomeMethod"
                placeholder="请选择"
                clearable
                style="width: 200px;"
              >
                <el-option
                  v-for="item in payment_methods"
                  :key="item.value"
                  :label="item.label"
                  :value="item.value"
                />
              </el-select>
      </el-form-item>
      <el-form-item>
        <el-button type="primary" @click="getTableData">搜索</el-button>
        <el-button @click="resetFilters">重置</el-button>
      </el-form-item>
    </el-form>
    <div class="table_list">
      <div class="actions">
        <div></div>
        <div>
          <el-button type="primary" @click="add" icon="Plus"> æ–°å¢ž </el-button>
          <el-button @click="handleOut" icon="download">导出</el-button>
          <el-button
            type="danger"
            icon="Delete"
            :disabled="multipleList.length <= 0"
            @click="deleteRow(multipleList.map((item) => item.id))"
          >
            æ‰¹é‡åˆ é™¤
          </el-button>
        </div>
      </div>
      <PIMTable
        rowKey="id"
        isSelection
        :column="columns"
        :tableData="dataList"
        :page="{
          current: pagination.currentPage,
          size: pagination.pageSize,
          total: pagination.total,
        }"
        @selection-change="handleSelectionChange"
        @pagination="changePage"
      >
        <template #operation="{ row }">
          <el-button type="primary" text @click="edit(row.id)" icon="editPen">
            ç¼–辑
          </el-button>
          <el-button
            type="primary"
            text
            @click="openFilesFormDia(row)"
          >
            é™„ä»¶
          </el-button>
        </template>
      </PIMTable>
    </div>
    <Modal ref="modalRef" @success="getTableData"></Modal>
    <files-dia ref="filesDia" @close="handleQuery"></files-dia>
  </div>
</template>
<script setup>
import { usePaginationApi } from "@/hooks/usePaginationApi";
import { listPage, delAccountIncome } 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";
defineOptions({
  name: "收入管理",
});
// è¡¨æ ¼å¤šé€‰æ¡†é€‰ä¸­é¡¹
const multipleList = ref([]);
const { proxy } = getCurrentInstance();
const modalRef = ref();
const { payment_methods } = proxy.useDict("payment_methods");
const { income_types } = proxy.useDict("income_types");
const filesDia = ref()
const {
  filters,
  columns,
  dataList,
  pagination,
  getTableData,
  resetFilters,
  onCurrentChange,
} = usePaginationApi(
  listPage,
  {
    incomeMethod: undefined,
  },
  [
    {
      label: "收入日期",
      align: "center",
      prop: "incomeDate",
    },
    {
      label: "收入类型",
      align: "center",
      prop: "incomeType",
      dataType: "tag",
      formatData: (params) => {
        if (income_types.value.find((m) => m.value == params)) {
          return income_types.value.find((m) => m.value == params).label;
        } else {
          return null
        }
      },
    },
    {
      label: "客户名称",
      align: "center",
      prop: "customerName",
    },
    {
      label: "收入金额",
      align: "center",
      prop: "incomeMoney",
    },
    {
      label: "收入描述",
      align: "center",
      prop: "incomeDescribed",
    },
    {
      label: "收款方式",
      align: "center",
      prop: "incomeMethod",
      dataType: "tag",
      formatData: (params) => {
        if (payment_methods.value.find((m) => m.value == params)) {
          return payment_methods.value.find((m) => m.value == params).label;
        } else {
          return null
        }
      },
    },
    {
      label: "发票号码",
      align: "center",
      prop: "invoiceNumber",
    },
    {
      label: "备注",
      align: "center",
      prop: "note",
    },
    {
      label: "录入人",
      align: "center",
      prop: "inputUser",
    },
    {
      label: "录入日期",
      align: "center",
      prop: "inputTime",
    },
    {
      fixed: "right",
      label: "操作",
      dataType: "slot",
      slot: "operation",
      align: "center",
      width: "200px",
    },
  ]
);
// å¤šé€‰åŽåšä»€ä¹ˆ
const handleSelectionChange = (selectionList) => {
  multipleList.value = selectionList;
};
const add = () => {
  modalRef.value.openModal();
};
const edit = (id) => {
  modalRef.value.loadForm(id);
};
const changePage = ({ page, limit }) => {
  pagination.currentPage = page;
    pagination.pageSize = limit;
  onCurrentChange(page);
};
const deleteRow = (id) => {
  ElMessageBox.confirm("此操作将永久删除该数据, æ˜¯å¦ç»§ç»­?", "提示", {
    confirmButtonText: "确定",
    cancelButtonText: "取消",
    type: "warning",
  }).then(async () => {
    const { code } = await delAccountIncome(id);
    if (code == 200) {
      ElMessage({
        type: "success",
        message: "删除成功",
      });
      getTableData();
    }
  });
};
const changeDaterange = (value) => {
  if (value) {
    filters.entryDateStart = dayjs(value[0]).format("YYYY-MM-DD");
    filters.entryDateEnd = dayjs(value[1]).format("YYYY-MM-DD");
  } else {
    filters.entryDateStart = undefined;
    filters.entryDateEnd = undefined;
  }
  getTableData();
};
const handleOut = () => {
  ElMessageBox.confirm("选中的内容将被导出,是否确认导出?", "导出", {
    confirmButtonText: "确认",
    cancelButtonText: "取消",
    type: "warning",
  })
    .then(() => {
      proxy.download(`/account/accountIncome/export`, {}, "收入台账.xlsx");
    })
    .catch(() => {
      proxy.$modal.msg("已取消");
    });
};
// æ‰“开附件弹框
const openFilesFormDia = (row) => {
  nextTick(() => {
    filesDia.value?.openDialog( row,'收入')
  })
};
onMounted(() => {
  filters.entryDate = [
    dayjs().format("YYYY-MM-DD"),
    dayjs().add(1, "day").format("YYYY-MM-DD"),
  ]
  filters.entryDateStart = dayjs().format("YYYY-MM-DD")
  filters.entryDateEnd = dayjs().add(1, "day").format("YYYY-MM-DD")
  getTableData();
});
</script>
<style lang="scss" scoped>
.table_list {
  margin-top: unset;
}
.actions {
  display: flex;
  justify-content: space-between;
  margin-bottom: 10px;
}
</style>
src/views/salesManagement/salesLedger/fileList.vue
@@ -1,22 +1,26 @@
<template>
  <el-dialog v-model="dialogVisible" title="附件" width="30%" :before-close="handleClose">
  <el-dialog v-model="dialogVisible" title="附件" width="40%" :before-close="handleClose">
    <el-table :data="tableData" border height="40vh">
      <el-table-column label="附件名称" prop="name" min-width="400" show-overflow-tooltip />
      <el-table-column fixed="right" label="操作" width="100" align="center">
        <template #default="scope">
          <el-button link type="primary" size="small" @click="downLoadFile(scope.row)">下载</el-button>
          <el-button link type="primary" size="small" @click="lookFile(scope.row)">预览</el-button>
        </template>
      </el-table-column>
    </el-table>
  </el-dialog>
  <filePreview ref="filePreviewRef" />
</template>
<script setup>
import { ref } from 'vue'
import filePreview from '@/components/filePreview/index.vue'
const dialogVisible = ref(false)
const tableData = ref([])
const { proxy } = getCurrentInstance();
const filePreviewRef = ref()
const handleClose = () => {
  dialogVisible.value = false
}
@@ -28,6 +32,9 @@
  proxy.$download.name(row.url);
}
const lookFile = (row) => {
  filePreviewRef.value.open(row.url)
}
defineExpose({
  open
})