index.vue 16 KB

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