index.vue 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660
  1. <template>
  2. <div class="tenant">
  3. <div class="content">
  4. <byTable
  5. :source="sourceList.data"
  6. :pagination="sourceList.pagination"
  7. :config="config"
  8. :loading="loading"
  9. :selectConfig="selectConfig"
  10. highlight-current-row
  11. :action-list="[
  12. {
  13. text: '导出Excel',
  14. action: () => deriveExcel(),
  15. },
  16. {
  17. text: '添加流水',
  18. action: () => openModal('add'),
  19. },
  20. ]"
  21. @moreSearch="moreSearch"
  22. @get-list="getList">
  23. <template #amount="{ item }">
  24. <div :style="'color: ' + (item.status === '10' ? '#04cb04;' : 'red;')">
  25. <span style="padding-right: 4px" v-if="item.currency">{{ item.currency }}</span>
  26. <span style="padding-right: 4px" v-else>
  27. {{ accountCurrency[0].value }}
  28. </span>
  29. <span v-if="item.status === '20'">-</span>
  30. <span>{{ moneyFormat(item.amount, 2) }}</span>
  31. </div>
  32. </template>
  33. <template #contractCodes="{ item }">
  34. <div style="width: 100%">
  35. <div v-if="item.contractCodes">
  36. <div v-for="(contract, index) in item.contractCodes.split(',')" :key="index">
  37. <a style="color: #409eff; cursor: pointer; word-break: break-all" @click="openDetails(contract)">{{ contract }}</a>
  38. </div>
  39. </div>
  40. </div>
  41. </template>
  42. </byTable>
  43. </div>
  44. <el-dialog :title="modalType == 'add' ? '添加流水' : '编辑流水'" v-if="dialogVisible" v-model="dialogVisible" width="600" v-loading="loadingDialog">
  45. <byForm :formConfig="formConfig" :formOption="formOption" v-model="formData.data" :rules="rules" ref="submit">
  46. <template #transactionTime>
  47. <div>
  48. <el-date-picker v-model="formData.data.transactionTime" type="datetime" placeholder="请选择交易时间" value-format="YYYY-MM-DD HH:mm:ss" />
  49. </div>
  50. </template>
  51. <template #money>
  52. <div style="width: 100%">
  53. <el-row :gutter="10">
  54. <el-col :span="6">
  55. <el-form-item prop="status">
  56. <el-select v-model="formData.data.status" placeholder="请选择" style="width: 100%" @change="changeStatus()">
  57. <el-option v-for="item in status" :key="item.value" :label="item.label" :value="item.value" />
  58. </el-select>
  59. </el-form-item>
  60. </el-col>
  61. <el-col :span="6">
  62. <el-form-item prop="currency">
  63. <el-select v-model="formData.data.currency" placeholder="请选择" style="width: 100%">
  64. <el-option v-for="item in accountCurrency" :key="item.value" :label="item.label" :value="item.value" />
  65. </el-select>
  66. </el-form-item>
  67. </el-col>
  68. <el-col :span="12">
  69. <el-form-item prop="amount">
  70. <el-input-number
  71. onmousewheel="return false;"
  72. v-model="formData.data.amount"
  73. placeholder="请输入金额"
  74. style="width: 100%"
  75. :precision="2"
  76. :controls="false"
  77. :min="0" />
  78. </el-form-item>
  79. </el-col>
  80. </el-row>
  81. </div>
  82. </template>
  83. <template #received>
  84. <div>
  85. <el-form-item prop="received">
  86. <el-radio-group v-model="formData.data.received">
  87. <el-radio v-for="item in received" :key="item.value" :label="item.value" border>{{ item.label }}</el-radio>
  88. </el-radio-group>
  89. </el-form-item>
  90. </div>
  91. </template>
  92. </byForm>
  93. <template #footer>
  94. <el-button @click="dialogVisible = false" size="large">取 消</el-button>
  95. <el-button type="primary" @click="submitForm()" size="large">确 定</el-button>
  96. </template>
  97. </el-dialog>
  98. <el-dialog title="高级检索" v-if="openSearch" v-model="openSearch" width="600" :before-close="cancelSearch">
  99. <byForm :formConfig="formSearchConfig" :formOption="formOption" v-model="sourceList.pagination">
  100. <template #money>
  101. <div style="width: 100%">
  102. <el-row :gutter="10">
  103. <el-col :span="11">
  104. <el-input-number
  105. onmousewheel="return false;"
  106. v-model="sourceList.pagination.beginAmount"
  107. placeholder="请输入"
  108. style="width: 100%"
  109. :precision="2"
  110. :controls="false"
  111. :min="0" />
  112. </el-col>
  113. <el-col :span="2" style="text-align: center">到</el-col>
  114. <el-col :span="11">
  115. <el-input-number
  116. onmousewheel="return false;"
  117. v-model="sourceList.pagination.endAmount"
  118. placeholder="请输入"
  119. style="width: 100%"
  120. :precision="2"
  121. :controls="false"
  122. :min="0" />
  123. </el-col>
  124. </el-row>
  125. </div>
  126. </template>
  127. <template #time>
  128. <div style="width: 100%">
  129. <el-row :gutter="10">
  130. <el-col :span="11">
  131. <el-date-picker
  132. v-model="sourceList.pagination.startTime"
  133. type="datetime"
  134. placeholder="请选择"
  135. style="width: 100%"
  136. value-format="YYYY-MM-DD HH:mm:ss" />
  137. </el-col>
  138. <el-col :span="2" style="text-align: center">到</el-col>
  139. <el-col :span="11">
  140. <el-date-picker
  141. v-model="sourceList.pagination.stopTime"
  142. type="datetime"
  143. placeholder="请选择"
  144. style="width: 100%"
  145. value-format="YYYY-MM-DD HH:mm:ss" />
  146. </el-col>
  147. </el-row>
  148. </div>
  149. </template>
  150. </byForm>
  151. <template #footer>
  152. <el-button @click="cancelSearch()" size="large">取 消</el-button>
  153. <el-button type="primary" @click="submitSearch()" size="large">确 定</el-button>
  154. </template>
  155. </el-dialog>
  156. <el-dialog title="打印" v-if="openPrint" v-model="openPrint" width="860">
  157. <ContractPDF :rowData="rowData"></ContractPDF>
  158. <template #footer>
  159. <el-button @click="openPrint = false" size="large">取消</el-button>
  160. <el-button v-print="printObj" size="large">打印</el-button>
  161. <el-button type="primary" @click="clickDownload()" size="large">下载PDF</el-button>
  162. </template>
  163. </el-dialog>
  164. </div>
  165. </template>
  166. <script setup>
  167. import { computed, ref } from "vue";
  168. import byTable from "@/components/byTable/index";
  169. import byForm from "@/components/byForm/index";
  170. import useUserStore from "@/store/modules/user";
  171. import { ElMessage, ElMessageBox } from "element-plus";
  172. import moment from "moment";
  173. import ContractPDF from "@/components/PDF/contractPDF.vue";
  174. const { proxy } = getCurrentInstance();
  175. const accountCurrency = ref([]);
  176. const accountList = ref([]);
  177. const status = ref([
  178. {
  179. label: "收入",
  180. value: "10",
  181. },
  182. {
  183. label: "支出",
  184. value: "20",
  185. },
  186. ]);
  187. const received = ref([
  188. {
  189. label: "是",
  190. value: "10",
  191. },
  192. {
  193. label: "否",
  194. value: "20",
  195. },
  196. ]);
  197. const sourceList = ref({
  198. data: [],
  199. pagination: {
  200. total: 0,
  201. pageNum: 1,
  202. pageSize: 10,
  203. keyword: "",
  204. accountManagementId: "",
  205. currency: "",
  206. status: "",
  207. received: "",
  208. beginAmount: undefined,
  209. endAmount: undefined,
  210. startTime: "",
  211. stopTime: "",
  212. remarks: "",
  213. },
  214. });
  215. const loading = ref(false);
  216. const selectConfig = computed(() => {
  217. return [
  218. {
  219. label: "收支类型",
  220. prop: "status",
  221. data: status.value,
  222. },
  223. {
  224. label: "资金账户",
  225. prop: "accountManagementId",
  226. data: accountList.value,
  227. },
  228. {
  229. label: "币种",
  230. prop: "currency",
  231. data: accountCurrency.value,
  232. },
  233. ];
  234. });
  235. const config = computed(() => {
  236. return [
  237. {
  238. attrs: {
  239. label: "归属公司",
  240. prop: "corporationName",
  241. width: 160,
  242. },
  243. },
  244. {
  245. attrs: {
  246. label: "关联销售合同",
  247. slot: "contractCodes",
  248. width: 160,
  249. },
  250. },
  251. {
  252. attrs: {
  253. label: "资金账户",
  254. prop: "accountManagementName",
  255. width: 200,
  256. },
  257. },
  258. {
  259. attrs: {
  260. label: "交易时间",
  261. prop: "transactionTime",
  262. width: 160,
  263. },
  264. },
  265. {
  266. attrs: {
  267. label: "交易金额",
  268. slot: "amount",
  269. width: 200,
  270. },
  271. },
  272. {
  273. attrs: {
  274. label: "对方账户",
  275. prop: "name",
  276. width: 200,
  277. },
  278. },
  279. {
  280. attrs: {
  281. label: "对方银行",
  282. prop: "openingBank",
  283. width: 200,
  284. },
  285. },
  286. {
  287. attrs: {
  288. label: "对方账号",
  289. prop: "accountOpening",
  290. width: 240,
  291. },
  292. },
  293. {
  294. attrs: {
  295. label: "摘要",
  296. prop: "remarks",
  297. },
  298. },
  299. {
  300. attrs: {
  301. label: "操作",
  302. width: "120",
  303. align: "center",
  304. },
  305. renderHTML(row) {
  306. return [
  307. {
  308. attrs: {
  309. label: "修改",
  310. type: "primary",
  311. text: true,
  312. },
  313. el: "button",
  314. click() {
  315. update(row);
  316. },
  317. },
  318. {
  319. attrs: {
  320. label: "删除",
  321. type: "primary",
  322. text: true,
  323. },
  324. el: "button",
  325. click() {
  326. ElMessageBox.confirm("此操作将永久删除该数据, 是否继续?", "提示", {
  327. confirmButtonText: "确定",
  328. cancelButtonText: "取消",
  329. type: "warning",
  330. }).then(() => {
  331. proxy
  332. .post("/accountRunningWater/delete", {
  333. id: row.id,
  334. })
  335. .then(() => {
  336. ElMessage({
  337. message: "删除成功",
  338. type: "success",
  339. });
  340. getList();
  341. });
  342. });
  343. },
  344. },
  345. ];
  346. },
  347. },
  348. ];
  349. });
  350. const getDict = () => {
  351. proxy
  352. .post("/dictTenantData/page", {
  353. pageNum: 1,
  354. pageSize: 999,
  355. dictCode: "account_currency",
  356. tenantId: useUserStore().user.tenantId,
  357. })
  358. .then((res) => {
  359. if (res.rows && res.rows.length > 0) {
  360. accountCurrency.value = res.rows.map((item) => {
  361. return {
  362. label: item.dictValue,
  363. value: item.dictKey,
  364. };
  365. });
  366. }
  367. });
  368. proxy.post("/accountManagement/page", { pageNum: 1, pageSize: 999 }).then((res) => {
  369. if (res.rows && res.rows.length > 0) {
  370. accountList.value = res.rows.map((item) => {
  371. return {
  372. label: item.alias,
  373. value: item.id,
  374. };
  375. });
  376. }
  377. });
  378. };
  379. const getList = async (req) => {
  380. sourceList.value.pagination = { ...sourceList.value.pagination, ...req };
  381. loading.value = true;
  382. proxy.post("/accountRunningWater/page", sourceList.value.pagination).then((res) => {
  383. sourceList.value.data = res.rows;
  384. sourceList.value.pagination.total = res.total;
  385. setTimeout(() => {
  386. loading.value = false;
  387. }, 200);
  388. });
  389. };
  390. getDict();
  391. getList();
  392. const modalType = ref("add");
  393. const dialogVisible = ref(false);
  394. const loadingDialog = ref(false);
  395. const submit = ref(null);
  396. const formOption = reactive({
  397. inline: true,
  398. labelWidth: 100,
  399. itemWidth: 100,
  400. rules: [],
  401. });
  402. const formData = reactive({
  403. data: {},
  404. });
  405. const formConfig = computed(() => {
  406. return [
  407. {
  408. label: "账户信息",
  409. },
  410. {
  411. type: "select",
  412. prop: "accountManagementId",
  413. label: "选择账户",
  414. data: accountList.value,
  415. },
  416. {
  417. label: "交易信息",
  418. },
  419. {
  420. type: "slot",
  421. prop: "transactionTime",
  422. slotName: "transactionTime",
  423. label: "交易时间",
  424. },
  425. {
  426. type: "slot",
  427. prop: "money",
  428. slotName: "money",
  429. label: "交易金额",
  430. },
  431. formData.data.status == "10"
  432. ? {
  433. type: "slot",
  434. prop: "received",
  435. slotName: "received",
  436. label: "合同到账",
  437. }
  438. : {},
  439. {
  440. label: "对方信息",
  441. },
  442. {
  443. type: "input",
  444. prop: "name",
  445. label: "账户名称",
  446. itemType: "text",
  447. },
  448. {
  449. type: "input",
  450. prop: "openingBank",
  451. label: "开户银行",
  452. itemType: "text",
  453. },
  454. {
  455. type: "input",
  456. prop: "accountOpening",
  457. label: "银行账号",
  458. itemType: "text",
  459. },
  460. {
  461. label: "其他信息",
  462. },
  463. {
  464. type: "input",
  465. prop: "remarks",
  466. label: "摘要",
  467. itemType: "textarea",
  468. },
  469. ];
  470. });
  471. const rules = ref({
  472. accountManagementId: [{ required: true, message: "请选择账户", trigger: "change" }],
  473. transactionTime: [{ required: true, message: "请选择交易时间", trigger: "change" }],
  474. status: [{ required: true, message: "请选择收支类型", trigger: "change" }],
  475. currency: [{ required: true, message: "请选择币种", trigger: "change" }],
  476. received: [{ required: true, message: "请选择合同是否到账", trigger: "change" }],
  477. amount: [{ required: true, message: "请输入金额", trigger: "blur" }],
  478. // name: [{ required: true, message: "请输入账户名称", trigger: "blur" }],
  479. // openingBank: [{ required: true, message: "请输入开户银行", trigger: "blur" }],
  480. // accountOpening: [{ required: true, message: "请输入银行账号", trigger: "blur" }],
  481. });
  482. const openModal = (val) => {
  483. modalType.value = val;
  484. formData.data = {
  485. transactionTime: moment().format("yyyy-MM-DD HH:mm:ss"),
  486. };
  487. loadingDialog.value = false;
  488. dialogVisible.value = true;
  489. };
  490. const changeStatus = () => {
  491. formData.data.received = "";
  492. };
  493. const submitForm = () => {
  494. submit.value.handleSubmit(() => {
  495. if (!formData.data.amount || Number(formData.data.amount) == 0) {
  496. return ElMessage("交易金额不能为0");
  497. }
  498. loadingDialog.value = true;
  499. proxy.post("/accountRunningWater/" + modalType.value, formData.data).then(
  500. () => {
  501. ElMessage({
  502. message: modalType.value == "add" ? "添加成功" : "编辑成功",
  503. type: "success",
  504. });
  505. dialogVisible.value = false;
  506. getList();
  507. },
  508. (err) => {
  509. console.log(err);
  510. loadingDialog.value = false;
  511. }
  512. );
  513. });
  514. };
  515. const update = (row) => {
  516. modalType.value = "edit";
  517. loadingDialog.value = true;
  518. proxy.post("/accountRunningWater/detail", { id: row.id }).then((res) => {
  519. formData.data = res;
  520. loadingDialog.value = false;
  521. });
  522. dialogVisible.value = true;
  523. };
  524. const deriveExcel = () => {
  525. let queryParams = proxy.deepClone(sourceList.value.pagination);
  526. queryParams.pageNum = 1;
  527. queryParams.pageSize = 9999;
  528. proxy.postTwo("/accountRunningWater/exportExcel", queryParams).then((res) => {
  529. exportData(res, "资金流水.xlsx");
  530. });
  531. };
  532. const exportData = (res, name) => {
  533. const content = res;
  534. const blob = new Blob([content], { type: "application/ms-excel" });
  535. const fileName = name;
  536. if ("download" in document.createElement("a")) {
  537. // 非IE下载
  538. const elink = document.createElement("a");
  539. elink.download = fileName;
  540. elink.style.display = "none";
  541. elink.href = URL.createObjectURL(blob);
  542. document.body.appendChild(elink);
  543. elink.click();
  544. URL.revokeObjectURL(elink.href); // 释放URL 对象
  545. document.body.removeChild(elink);
  546. } else {
  547. navigator.msSaveBlob(blob, fileName);
  548. }
  549. };
  550. const openSearch = ref(false);
  551. const formSearchConfig = computed(() => {
  552. return [
  553. {
  554. type: "select",
  555. prop: "accountManagementId",
  556. label: "资金账户",
  557. data: accountList.value,
  558. clearable: true,
  559. },
  560. {
  561. type: "select",
  562. prop: "status",
  563. label: "交易类型",
  564. data: status.value,
  565. itemWidth: 50,
  566. clearable: true,
  567. },
  568. {
  569. type: "select",
  570. prop: "received",
  571. label: "是否合同到账",
  572. data: received.value,
  573. itemWidth: 50,
  574. clearable: true,
  575. },
  576. {
  577. type: "select",
  578. prop: "currency",
  579. label: "币种",
  580. data: accountCurrency.value,
  581. clearable: true,
  582. },
  583. {
  584. type: "slot",
  585. slotName: "money",
  586. label: "交易金额",
  587. },
  588. {
  589. type: "slot",
  590. slotName: "time",
  591. label: "交易时间",
  592. },
  593. {
  594. type: "input",
  595. prop: "remarks",
  596. label: "摘要",
  597. itemType: "text",
  598. },
  599. ];
  600. });
  601. let copySearch = ref({});
  602. const moreSearch = () => {
  603. copySearch.value = proxy.deepClone(sourceList.value.pagination);
  604. openSearch.value = true;
  605. };
  606. const cancelSearch = () => {
  607. sourceList.value.pagination = copySearch.value;
  608. openSearch.value = false;
  609. };
  610. const submitSearch = () => {
  611. if (
  612. sourceList.value.pagination.beginAmount &&
  613. sourceList.value.pagination.endAmount &&
  614. Number(sourceList.value.pagination.beginAmount) > Number(sourceList.value.pagination.endAmount)
  615. ) {
  616. return ElMessage("交易金额输入错误");
  617. }
  618. if (
  619. sourceList.value.pagination.startTime &&
  620. sourceList.value.pagination.stopTime &&
  621. sourceList.value.pagination.startTime > sourceList.value.pagination.stopTime
  622. ) {
  623. return ElMessage("开始时间不能大于结束时间");
  624. }
  625. openSearch.value = false;
  626. sourceList.value.pagination.pageNum = 1;
  627. getList();
  628. };
  629. const openPrint = ref(false);
  630. const rowData = ref({});
  631. const openDetails = (val) => {
  632. rowData.value = {
  633. code: val,
  634. };
  635. openPrint.value = true;
  636. };
  637. const printObj = ref({
  638. id: "printMe",
  639. popTitle: "",
  640. extraCss: "https://cdn.bootcdn.net/ajax/libs/animate.css/4.1.1/animate.compat.css, https://cdn.bootcdn.net/ajax/libs/hover.css/2.3.1/css/hover-min.css",
  641. extraHead: '<meta http-equiv="Content-Language"content="zh-cn"/>',
  642. });
  643. const clickDownload = () => {
  644. proxy.getPdf("外销合同PDF文件");
  645. };
  646. </script>
  647. <style lang="scss" scoped>
  648. .tenant {
  649. padding: 20px;
  650. }
  651. ::v-deep(.el-input-number .el-input__inner) {
  652. text-align: left;
  653. }
  654. </style>