index.vue 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719
  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. highlight-current-row
  10. :selectConfig="selectConfig"
  11. :action-list="[
  12. {
  13. text: '发起请款',
  14. action: () => openModal(),
  15. },
  16. ]"
  17. @moreSearch="moreSearch"
  18. @get-list="getList"
  19. >
  20. <template #total="{ item }">
  21. <div style="width: 100%">
  22. <a
  23. style="color: #409eff; cursor: pointer"
  24. @click="pushProcessApproval(item)"
  25. >{{ item.currency }}{{ item.total }}</a
  26. >
  27. </div>
  28. </template>
  29. <template #type="{ item }">
  30. <div style="width: 100%">
  31. <span>
  32. {{ dictValueLabel(item.type, fundsType) }}
  33. </span>
  34. <span v-if="item.type == 1"
  35. >(<span v-if="item.writeOffStatus == 0">未核销</span
  36. ><span v-if="item.writeOffStatus == 1">已核销</span>)</span
  37. >
  38. </div>
  39. </template>
  40. <template #file="{ item }">
  41. <div style="width: 100%">
  42. <el-button type="primary" text @click="handleOpenFile(item)"
  43. >查看</el-button
  44. >
  45. </div>
  46. </template>
  47. </byTable>
  48. </div>
  49. <el-dialog title="打印" v-if="openPrint" v-model="openPrint" width="840px">
  50. <FundsPDF :rowData="rowData"></FundsPDF>
  51. <template #footer>
  52. <el-button @click="openPrint = false" size="large">取消</el-button>
  53. <el-button type="primary" v-print="printObj" size="large"
  54. >打印</el-button
  55. >
  56. <el-button type="primary" @click="clickDownload()" size="large"
  57. >下载PDF</el-button
  58. >
  59. </template>
  60. </el-dialog>
  61. <el-dialog
  62. title="高级检索"
  63. v-if="openSearch"
  64. v-model="openSearch"
  65. width="600"
  66. :before-close="cancelSearch"
  67. >
  68. <byForm
  69. :formConfig="formSearchConfig"
  70. :formOption="formOption"
  71. v-model="sourceList.pagination"
  72. >
  73. <template #departmentId>
  74. <div>
  75. <el-tree-select
  76. v-model="sourceList.pagination.departmentId"
  77. :data="deptTreeData"
  78. check-strictly
  79. :render-after-expand="false"
  80. node-key="deptId"
  81. style="width: 100%"
  82. :props="defaultProps"
  83. clearable
  84. />
  85. </div>
  86. </template>
  87. <template #time>
  88. <div style="width: 100%">
  89. <el-row :gutter="10">
  90. <el-col :span="11">
  91. <el-date-picker
  92. v-model="sourceList.pagination.beginTime"
  93. type="datetime"
  94. placeholder="请选择"
  95. style="width: 100%"
  96. value-format="YYYY-MM-DD HH:mm:ss"
  97. />
  98. </el-col>
  99. <el-col :span="2" style="text-align: center">到</el-col>
  100. <el-col :span="11">
  101. <el-date-picker
  102. v-model="sourceList.pagination.endTime"
  103. type="datetime"
  104. placeholder="请选择"
  105. style="width: 100%"
  106. value-format="YYYY-MM-DD HH:mm:ss"
  107. />
  108. </el-col>
  109. </el-row>
  110. </div>
  111. </template>
  112. <template #money>
  113. <div style="width: 100%">
  114. <el-row :gutter="10">
  115. <el-col :span="11">
  116. <el-input-number
  117. onmousewheel="return false;"
  118. v-model="sourceList.pagination.minAdvanceAmounts"
  119. placeholder="请输入"
  120. style="width: 100%"
  121. :precision="2"
  122. :controls="false"
  123. :min="0"
  124. />
  125. </el-col>
  126. <el-col :span="2" style="text-align: center">到</el-col>
  127. <el-col :span="11">
  128. <el-input-number
  129. onmousewheel="return false;"
  130. v-model="sourceList.pagination.maxAdvanceAmounts"
  131. placeholder="请输入"
  132. style="width: 100%"
  133. :precision="2"
  134. :controls="false"
  135. :min="0"
  136. />
  137. </el-col>
  138. </el-row>
  139. </div>
  140. </template>
  141. </byForm>
  142. <template #footer>
  143. <el-button @click="cancelSearch()" size="large">取 消</el-button>
  144. <el-button type="primary" @click="submitSearch()" size="large"
  145. >确 定</el-button
  146. >
  147. </template>
  148. </el-dialog>
  149. <el-dialog
  150. title="关联附件"
  151. v-if="openFileDialog"
  152. v-model="openFileDialog"
  153. width="500"
  154. >
  155. <byForm
  156. :formConfig="fileConfig"
  157. :formOption="formOption"
  158. v-model="fileData.data"
  159. >
  160. <template #fundsFile>
  161. <div
  162. style="width: 100%"
  163. v-if="fileData.data && fileData.data.fileList.length > 0"
  164. >
  165. <div v-for="(item, index) in fileData.data.fileList" :key="index">
  166. <div
  167. style="cursor: pointer; color: #409eff"
  168. @click="openFile(item)"
  169. >
  170. {{ item.fileName }}
  171. </div>
  172. </div>
  173. </div>
  174. <div v-else>暂无关联</div>
  175. </template>
  176. </byForm>
  177. <template #footer>
  178. <el-button @click="openFileDialog = false" size="large"
  179. >取 消</el-button
  180. >
  181. </template>
  182. </el-dialog>
  183. </div>
  184. </template>
  185. <script setup>
  186. import byTable from "@/components/byTable/index";
  187. import useUserStore from "@/store/modules/user";
  188. import { ref } from "vue";
  189. import byForm from "@/components/byForm/index";
  190. import FundsPDF from "@/components/PDF/fundsPDF.vue";
  191. const loading = ref(false);
  192. const sourceList = ref({
  193. data: [],
  194. pagination: {
  195. total: 0,
  196. pageNum: 1,
  197. pageSize: 10,
  198. type: "",
  199. keyword: "",
  200. writeOffStatus: "",
  201. corporationId: "",
  202. departmentId: "",
  203. createUser: "",
  204. currency: "",
  205. beginTime: "",
  206. endTime: "",
  207. minAdvanceAmounts: undefined,
  208. maxAdvanceAmounts: undefined,
  209. paymentRemarks: "",
  210. paymentMethod: "",
  211. status: "",
  212. paymentStatus: "",
  213. },
  214. });
  215. const { proxy } = getCurrentInstance();
  216. const fundsType = ref([]);
  217. const userList = ref([]);
  218. const companyData = ref([]);
  219. const accountCurrency = ref([]);
  220. const fundsPaymentMethod = ref([]);
  221. const deptTreeData = ref([]);
  222. const status = ref([
  223. {
  224. label: "审批中",
  225. value: "10",
  226. },
  227. {
  228. label: "驳回",
  229. value: "20",
  230. },
  231. {
  232. label: "审批通过",
  233. value: "30",
  234. },
  235. ]);
  236. const paymentStatus = ref([
  237. {
  238. label: "已打款",
  239. value: "10",
  240. },
  241. {
  242. label: "未打款",
  243. value: "20",
  244. },
  245. ]);
  246. const selectConfig = computed(() => {
  247. return [
  248. {
  249. label: "类型",
  250. prop: "type",
  251. data: fundsType.value,
  252. },
  253. {
  254. label: "审批状态",
  255. prop: "status",
  256. data: status.value,
  257. },
  258. {
  259. label: "放款状态",
  260. prop: "paymentStatus",
  261. data: paymentStatus.value,
  262. },
  263. ];
  264. });
  265. const config = computed(() => {
  266. return [
  267. {
  268. attrs: {
  269. label: "归属公司",
  270. prop: "corporationName",
  271. width: 180,
  272. },
  273. },
  274. {
  275. attrs: {
  276. label: "归属部门",
  277. prop: "deptName",
  278. width: 140,
  279. },
  280. },
  281. {
  282. attrs: {
  283. label: "请款类型",
  284. prop: "type",
  285. width: 130,
  286. slot: "type",
  287. },
  288. },
  289. {
  290. attrs: {
  291. label: "请款人",
  292. prop: "userName",
  293. width: 120,
  294. },
  295. },
  296. {
  297. attrs: {
  298. label: "请款时间",
  299. prop: "createTime",
  300. width: 160,
  301. },
  302. },
  303. {
  304. attrs: {
  305. label: "请款金额",
  306. slot: "total",
  307. width: 120,
  308. },
  309. },
  310. {
  311. attrs: {
  312. label: "用款说明",
  313. prop: "paymentRemarks",
  314. "min-width": 180,
  315. },
  316. },
  317. {
  318. attrs: {
  319. label: "关联附件",
  320. slot: "file",
  321. width: 80,
  322. align: "left",
  323. },
  324. },
  325. {
  326. attrs: {
  327. label: "付款方式",
  328. prop: "paymentMethod",
  329. width: 120,
  330. },
  331. render(paymentMethod) {
  332. return proxy.dictValueLabel(paymentMethod, fundsPaymentMethod.value);
  333. },
  334. },
  335. {
  336. attrs: {
  337. label: "付款账户",
  338. prop: "accountManagementName",
  339. width: 160,
  340. },
  341. },
  342. {
  343. attrs: {
  344. label: "审批状态",
  345. prop: "status",
  346. width: 120,
  347. },
  348. render(status) {
  349. return status == 10
  350. ? "审批中"
  351. : status == 20
  352. ? "驳回"
  353. : status == 30
  354. ? "审批通过"
  355. : "";
  356. },
  357. },
  358. {
  359. attrs: {
  360. label: "放款状态",
  361. prop: "accountPaymentStatus",
  362. width: 120,
  363. },
  364. render(status) {
  365. return proxy.dictValueLabel(status, paymentStatus.value);
  366. },
  367. },
  368. {
  369. attrs: {
  370. label: "操作",
  371. width: "120",
  372. align: "center",
  373. fixed: "right",
  374. },
  375. renderHTML(row) {
  376. return [
  377. row.type == 1 && row.writeOffStatus == 0 && row.status == "30"
  378. ? {
  379. attrs: {
  380. label: "核销",
  381. type: "primary",
  382. text: true,
  383. },
  384. el: "button",
  385. click() {
  386. openModal(row);
  387. },
  388. }
  389. : {},
  390. {
  391. attrs: {
  392. label: "打印",
  393. type: "primary",
  394. text: true,
  395. },
  396. el: "button",
  397. click() {
  398. clickPrint(row);
  399. },
  400. },
  401. ];
  402. },
  403. },
  404. ];
  405. });
  406. const getList = async (req) => {
  407. sourceList.value.pagination = { ...sourceList.value.pagination, ...req };
  408. loading.value = true;
  409. proxy
  410. .post("/accountRequestFunds/page", sourceList.value.pagination)
  411. .then((message) => {
  412. sourceList.value.data = message.rows;
  413. sourceList.value.pagination.total = message.total;
  414. setTimeout(() => {
  415. loading.value = false;
  416. }, 200);
  417. });
  418. };
  419. const openModal = (row = {}) => {
  420. const flowName = `${userInfo.nickName}的请款申请(发起)`;
  421. let query = {
  422. flowKey: "account_request_funds_flow",
  423. random: proxy.random(),
  424. flowName,
  425. };
  426. if (row.id) {
  427. query.advanceId = row.id;
  428. query.corporationId = row.corporationId;
  429. }
  430. proxy.$router.replace({
  431. path: "/platform_manage/process/processApproval",
  432. query,
  433. });
  434. };
  435. const userInfo = useUserStore().user;
  436. const recursive = (data) => {
  437. data.map((item) => {
  438. item.label = item.deptName;
  439. item.id = item.corporationId;
  440. if (item.children) {
  441. recursive(item.children);
  442. } else {
  443. item.children = [];
  444. }
  445. });
  446. };
  447. const getDictData = () => {
  448. proxy
  449. .getDictOne(["founds_type", "funds_payment_method", "account_currency"])
  450. .then((res) => {
  451. fundsType.value = res["founds_type"].map((x) => ({
  452. label: x.dictValue,
  453. value: x.dictKey,
  454. }));
  455. fundsPaymentMethod.value = res["funds_payment_method"].map((x) => ({
  456. label: x.dictValue,
  457. value: x.dictKey,
  458. }));
  459. accountCurrency.value = res["account_currency"].map((x) => ({
  460. label: x.dictValue,
  461. value: x.dictKey,
  462. }));
  463. });
  464. proxy
  465. .get("/tenantUser/list", {
  466. pageNum: 1,
  467. pageSize: 10000,
  468. tenantId: useUserStore().user.tenantId,
  469. })
  470. .then((res) => {
  471. if (res.rows && res.rows.length > 0) {
  472. userList.value = res.rows.map((item) => {
  473. return {
  474. deptId: item.deptId,
  475. label: item.nickName,
  476. value: item.userId,
  477. };
  478. });
  479. }
  480. });
  481. proxy
  482. .post("/corporation/page", { pageNum: 1, pageSize: 9999 })
  483. .then((res) => {
  484. if (res.rows && res.rows.length > 0) {
  485. companyData.value = res.rows.map((item) => {
  486. return {
  487. label: item.name,
  488. value: item.id,
  489. };
  490. });
  491. }
  492. });
  493. proxy
  494. .get("/tenantDept/list", {
  495. pageNum: 1,
  496. pageSize: 9999,
  497. tenantId: userInfo.tenantId,
  498. })
  499. .then((message) => {
  500. recursive(message.data);
  501. deptTreeData.value = [];
  502. let data = proxy.handleTree(message.data, "deptId");
  503. if (data && data.length > 0) {
  504. for (let i = 0; i < data.length; i++) {
  505. if (data[i].children && data[i].children.length > 0) {
  506. deptTreeData.value = deptTreeData.value.concat(data[i].children);
  507. }
  508. }
  509. }
  510. });
  511. };
  512. getDictData();
  513. getList();
  514. const openPrint = ref(false);
  515. const rowData = ref({});
  516. const clickPrint = (row) => {
  517. rowData.value = row;
  518. openPrint.value = true;
  519. };
  520. const clickDownload = () => {
  521. proxy.getPdf("请款PDF文件");
  522. };
  523. const formOption = reactive({
  524. inline: true,
  525. labelWidth: 100,
  526. itemWidth: 100,
  527. rules: [],
  528. });
  529. const defaultProps = {
  530. children: "children",
  531. label: "deptName",
  532. };
  533. const openSearch = ref(false);
  534. const formSearchConfig = computed(() => {
  535. return [
  536. {
  537. type: "select",
  538. prop: "corporationId",
  539. label: "归属公司",
  540. data: companyData.value,
  541. clearable: true,
  542. filterable: true,
  543. },
  544. {
  545. type: "slot",
  546. slotName: "departmentId",
  547. label: "归属部门",
  548. itemWidth: 50,
  549. },
  550. {
  551. type: "select",
  552. prop: "createUser",
  553. label: "请款人",
  554. data: userList.value,
  555. itemWidth: 50,
  556. clearable: true,
  557. filterable: true,
  558. },
  559. {
  560. type: "select",
  561. prop: "type",
  562. label: "请款类型",
  563. data: fundsType.value,
  564. clearable: true,
  565. filterable: true,
  566. },
  567. {
  568. type: "select",
  569. prop: "currency",
  570. label: "币种",
  571. data: accountCurrency.value,
  572. clearable: true,
  573. filterable: true,
  574. },
  575. {
  576. type: "slot",
  577. slotName: "time",
  578. label: "请款时间",
  579. },
  580. {
  581. type: "slot",
  582. slotName: "money",
  583. label: "请款金额",
  584. },
  585. {
  586. type: "input",
  587. itemType: "textarea",
  588. prop: "paymentRemarks",
  589. label: "用款说明",
  590. },
  591. {
  592. type: "select",
  593. prop: "paymentMethod",
  594. label: "付款方式",
  595. data: fundsPaymentMethod.value,
  596. clearable: true,
  597. itemWidth: 50,
  598. filterable: true,
  599. },
  600. {
  601. type: "input",
  602. prop: "oppositeAccountName",
  603. label: "对方账户",
  604. itemWidth: 50,
  605. },
  606. {
  607. type: "select",
  608. prop: "status",
  609. label: "流程状态",
  610. data: status.value,
  611. itemWidth: 50,
  612. clearable: true,
  613. filterable: true,
  614. },
  615. {
  616. type: "select",
  617. prop: "paymentStatus",
  618. label: "打款状态",
  619. data: paymentStatus.value,
  620. itemWidth: 50,
  621. clearable: true,
  622. filterable: true,
  623. },
  624. ];
  625. });
  626. let copySearch = ref({});
  627. const moreSearch = () => {
  628. copySearch.value = proxy.deepClone(sourceList.value.pagination);
  629. openSearch.value = true;
  630. };
  631. const cancelSearch = () => {
  632. sourceList.value.pagination = copySearch.value;
  633. openSearch.value = false;
  634. };
  635. const submitSearch = () => {
  636. if (
  637. sourceList.value.pagination.minAdvanceAmounts &&
  638. sourceList.value.pagination.maxAdvanceAmounts &&
  639. Number(sourceList.value.pagination.minAdvanceAmounts) >
  640. Number(sourceList.value.pagination.maxAdvanceAmounts)
  641. ) {
  642. return ElMessage("交易金额输入错误");
  643. }
  644. if (
  645. sourceList.value.pagination.beginTime &&
  646. sourceList.value.pagination.endTime &&
  647. sourceList.value.pagination.beginTime > sourceList.value.pagination.endTime
  648. ) {
  649. return ElMessage("开始时间不能大于结束时间");
  650. }
  651. openSearch.value = false;
  652. sourceList.value.pagination.keyword = "";
  653. sourceList.value.pagination.pageNum = 1;
  654. getList();
  655. };
  656. const pushProcessApproval = (row) => {
  657. proxy.$router.push({
  658. path: "/platform_manage/process/processApproval",
  659. query: {
  660. flowKey: "account_request_funds_flow",
  661. id: row.flowInfoId,
  662. processType: 20,
  663. random: proxy.random(),
  664. flowName: "请款详情",
  665. businessId: row.id,
  666. },
  667. });
  668. return;
  669. };
  670. const printObj = ref({
  671. id: "pdfDom",
  672. popTitle: "",
  673. extraCss:
  674. "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",
  675. extraHead: '<meta http-equiv="Content-Language"content="zh-cn"/>',
  676. });
  677. const fileData = reactive({
  678. data: {},
  679. });
  680. const fileConfig = computed(() => [
  681. {
  682. type: "slot",
  683. slotName: "fundsFile",
  684. // label: "业务附件",
  685. },
  686. ]);
  687. const openFileDialog = ref(false);
  688. const handleOpenFile = (row) => {
  689. fileData.data = {
  690. fileList: [],
  691. };
  692. proxy
  693. .post("/fileInfo/getList", { businessIdList: [row.id] })
  694. .then((fileObj) => {
  695. if (fileObj[row.id] && fileObj[row.id].length > 0) {
  696. fileData.data.fileList = fileObj[row.id];
  697. }
  698. });
  699. openFileDialog.value = true;
  700. };
  701. const openFile = (item) => {
  702. window.open(item.fileUrl, "_blank");
  703. };
  704. </script>
  705. <style lang="scss" scoped>
  706. .tenant {
  707. padding: 20px;
  708. }
  709. ::v-deep(.el-input-number .el-input__inner) {
  710. text-align: left;
  711. }
  712. </style>