index.vue 18 KB

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