PurchasePayment.vue 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494
  1. <template>
  2. <div style="width: 100%; padding: 0px 15px">
  3. <byForm :formConfig="formConfig" :formOption="formOption" v-model="formData.data" :rules="rules" ref="submit">
  4. <template #deadline>
  5. <div>
  6. <el-date-picker v-model="formData.data.deadline" type="date" placeholder="请选择付款期限" value-format="YYYY-MM-DD" />
  7. </div>
  8. </template>
  9. <template #receiptsNum>
  10. <div>
  11. <el-input-number
  12. onmousewheel="return false;"
  13. v-model="formData.data.receiptsNum"
  14. placeholder="请输入单据数量"
  15. :min="0"
  16. :precision="0"
  17. :controls="false" />
  18. </div>
  19. </template>
  20. <template #fileList>
  21. <div style="width: 100%">
  22. <el-upload
  23. v-model:fileList="fileList"
  24. action="https://winfaster.obs.cn-south-1.myhuaweicloud.com"
  25. multiple
  26. :data="uploadData"
  27. :before-upload="uploadFile"
  28. :on-preview="onPreviewFile">
  29. <el-button>选择</el-button>
  30. </el-upload>
  31. </div>
  32. </template>
  33. <template #payDetailList>
  34. <div style="width: 100%">
  35. <el-button type="primary" @click="clickAdd()">添加行</el-button>
  36. <el-table :data="formData.data.payDetailList" style="width: 100%; margin-top: 16px">
  37. <el-table-column label="采购合同" width="220">
  38. <template #default="{ row, $index }">
  39. <div style="width: 100%">
  40. <el-form-item :prop="'payDetailList.' + $index + '.purchaseId'" :rules="rules.purchaseId" :inline-message="true">
  41. <el-select v-model="row.purchaseId" placeholder="请选择采购合同" style="width: 100%" @change="changePurchaseId(row)">
  42. <el-option v-for="item in contractList" :key="item.value" :label="item.label" :value="item.value" />
  43. </el-select>
  44. </el-form-item>
  45. </div>
  46. </template>
  47. </el-table-column>
  48. <el-table-column prop="amount" label="合同金额" width="140" />
  49. <el-table-column prop="sumPayMoney" label="已收发票金额" width="140" />
  50. <el-table-column label="款项说明">
  51. <template #default="{ row, $index }">
  52. <div style="width: 100%">
  53. <el-form-item :prop="'payDetailList.' + $index + '.remark'" :rules="rules.remark" :inline-message="true">
  54. <el-input v-model="row.remark" placeholder="请输入款项说明" style="width: 100%" />
  55. </el-form-item>
  56. </div>
  57. </template>
  58. </el-table-column>
  59. <el-table-column label="付款金额" width="180">
  60. <template #default="{ row, $index }">
  61. <div style="width: 100%">
  62. <el-form-item :prop="'payDetailList.' + $index + '.money'" :rules="rules.money" :inline-message="true">
  63. <el-input-number
  64. onmousewheel="return false;"
  65. v-model="row.money"
  66. placeholder="请输入金额"
  67. style="width: 100%"
  68. :precision="2"
  69. :controls="false"
  70. :min="0"
  71. :disabled="row.id"
  72. @change="changeMoney()" />
  73. </el-form-item>
  74. </div>
  75. </template>
  76. </el-table-column>
  77. <el-table-column label="操作" width="80">
  78. <template #default="{ row, $index }">
  79. <el-button type="primary" link @click="handleRemove($index)">删除</el-button>
  80. </template>
  81. </el-table-column>
  82. </el-table>
  83. <br />
  84. </div>
  85. </template>
  86. </byForm>
  87. </div>
  88. </template>
  89. <script setup>
  90. import byForm from "@/components/byForm/index";
  91. import { ElMessage } from "element-plus";
  92. import useUserStore from "@/store/modules/user";
  93. import { useRoute } from "vue-router";
  94. const route = useRoute();
  95. const { proxy } = getCurrentInstance();
  96. const supplierList = ref([]);
  97. const invoiceType = ref([]);
  98. const fundsPaymentMethod = ref([]);
  99. const accountList = ref([]);
  100. const contractList = ref([]);
  101. let formData = reactive({
  102. data: {
  103. supplyId: "",
  104. amount: "",
  105. invoiceType: "",
  106. remark: "",
  107. deadline: "",
  108. receiptsNum: undefined,
  109. payType: "",
  110. currency: "",
  111. accountManagementId: "",
  112. userName: "",
  113. payDetailList: [],
  114. fileList: [],
  115. },
  116. });
  117. const submit = ref(null);
  118. const judgeStatus = () => {
  119. if (props.queryData.recordList && props.queryData.recordList.length > 0) {
  120. let data = props.queryData.recordList.filter((item) => item.status === 2 && item.nodeType !== 1);
  121. if (data && data.length > 0) {
  122. return true;
  123. }
  124. }
  125. return false;
  126. };
  127. const formOption = reactive({
  128. inline: true,
  129. labelWidth: 100,
  130. itemWidth: 100,
  131. rules: [],
  132. disabled: false,
  133. });
  134. const formConfig = computed(() => {
  135. return [
  136. {
  137. type: "title",
  138. title: "基础信息",
  139. label: "",
  140. },
  141. {
  142. type: "select",
  143. label: "供应商",
  144. prop: "supplyId",
  145. data: supplierList.value,
  146. fn: (val) => {
  147. changeSupply(val);
  148. },
  149. },
  150. {
  151. type: "slot",
  152. prop: "deadline",
  153. slotName: "deadline",
  154. label: "付款期限",
  155. itemWidth: 50,
  156. },
  157. {
  158. type: "select",
  159. label: "发票类型",
  160. prop: "invoiceType",
  161. data: invoiceType.value,
  162. itemWidth: 50,
  163. },
  164. {
  165. type: "input",
  166. prop: "remark",
  167. label: "付款说明",
  168. itemType: "textarea",
  169. },
  170. {
  171. type: "slot",
  172. prop: "receiptsNum",
  173. slotName: "receiptsNum",
  174. label: "单据数量",
  175. },
  176. {
  177. type: "slot",
  178. prop: "fileList",
  179. slotName: "fileList",
  180. label: "上传附件",
  181. },
  182. {
  183. type: "slot",
  184. prop: "payDetailList",
  185. slotName: "payDetailList",
  186. label: "付款明细",
  187. },
  188. {
  189. type: "input",
  190. prop: "amount",
  191. label: "付款总额",
  192. required: true,
  193. itemType: "text",
  194. disabled: true,
  195. itemWidth: 50,
  196. },
  197. {
  198. label: "收款信息",
  199. },
  200. {
  201. type: "select",
  202. label: "付款方式",
  203. prop: "payType",
  204. data: fundsPaymentMethod.value,
  205. itemWidth: 50,
  206. },
  207. {
  208. type: "select",
  209. label: "付款账户",
  210. prop: "accountManagementId",
  211. data: accountList.value,
  212. itemWidth: 50,
  213. fn: (val) => {
  214. changeAccount(val);
  215. },
  216. },
  217. {
  218. type: "input",
  219. prop: "name",
  220. label: "户名",
  221. required: true,
  222. itemType: "text",
  223. itemWidth: 50,
  224. },
  225. {
  226. type: "input",
  227. prop: "accountOpening",
  228. label: "银行账号",
  229. required: true,
  230. itemType: "text",
  231. itemWidth: 50,
  232. },
  233. {
  234. type: "input",
  235. prop: "openingBank",
  236. label: "开户银行",
  237. required: true,
  238. itemType: "text",
  239. itemWidth: 50,
  240. },
  241. {
  242. type: "input",
  243. prop: "interbankNumber",
  244. label: "联行号",
  245. required: true,
  246. itemType: "text",
  247. itemWidth: 50,
  248. },
  249. ];
  250. });
  251. const rules = ref({
  252. supplyId: [{ required: true, message: "请选择供应商", trigger: "change" }],
  253. invoiceType: [{ required: true, message: "请选择发票类型", trigger: "change" }],
  254. payType: [{ required: true, message: "请选择付款方式", trigger: "change" }],
  255. // accountManagementId: [{ required: true, message: "请选择付款账户", trigger: "change" }],
  256. purchaseId: [{ required: true, message: "请选择采购合同", trigger: "change" }],
  257. money: [{ required: true, message: "请输入付款金额", trigger: "blur" }],
  258. name: [{ required: true, message: "请输入户名", trigger: "blur" }],
  259. });
  260. const fileList = ref([]);
  261. const uploadData = ref({});
  262. const getDict = () => {
  263. proxy
  264. .post("/dictTenantData/page", {
  265. pageNum: 1,
  266. pageSize: 999,
  267. dictCode: "invoice_type",
  268. tenantId: useUserStore().user.tenantId,
  269. })
  270. .then((res) => {
  271. if (res.rows && res.rows.length > 0) {
  272. invoiceType.value = res.rows.map((item) => {
  273. return {
  274. label: item.dictValue,
  275. value: item.dictKey,
  276. };
  277. });
  278. }
  279. });
  280. proxy
  281. .post("/dictTenantData/page", {
  282. pageNum: 1,
  283. pageSize: 999,
  284. dictCode: "funds_payment_method",
  285. tenantId: useUserStore().user.tenantId,
  286. })
  287. .then((res) => {
  288. if (res.rows && res.rows.length > 0) {
  289. fundsPaymentMethod.value = res.rows.map((item) => {
  290. return {
  291. label: item.dictValue,
  292. value: item.dictKey,
  293. };
  294. });
  295. }
  296. });
  297. proxy.post("/supplierInfo/page", { pageNum: 1, pageSize: 999 }).then((res) => {
  298. if (res.rows && res.rows.length > 0) {
  299. supplierList.value = res.rows.map((item) => {
  300. return {
  301. label: item.name,
  302. value: item.id,
  303. };
  304. });
  305. }
  306. });
  307. proxy.post("/accountManagement/page", { pageNum: 1, pageSize: 999 }).then((res) => {
  308. accountList.value = res.rows.map((item) => {
  309. return {
  310. bankName: item.name,
  311. accountOpening: item.accountOpening,
  312. openingBank: item.openingBank,
  313. interbankNumber: item.interbankNumber,
  314. label: item.alias,
  315. value: item.id,
  316. };
  317. });
  318. });
  319. };
  320. getDict();
  321. const uploadFile = async (file) => {
  322. const res = await proxy.post("/fileInfo/getSing", { fileName: file.name });
  323. uploadData.value = res.uploadBody;
  324. file.id = res.id;
  325. file.fileName = res.fileName;
  326. file.fileUrl = res.fileUrl;
  327. return true;
  328. };
  329. const onPreviewFile = (file) => {
  330. window.open(file.raw.fileUrl, "_blank");
  331. };
  332. const changeSupply = async (val) => {
  333. if (val) {
  334. await proxy.get("/purchase/getListBySupplyId", { supplyId: val }).then((res) => {
  335. if (res.data && res.data.length > 0) {
  336. contractList.value = res.data.map((item) => {
  337. return {
  338. value: item.id,
  339. label: item.code,
  340. amount: item.amount,
  341. sumPayMoney: item.sumPayMoney,
  342. };
  343. });
  344. } else {
  345. contractList.value = [];
  346. }
  347. });
  348. } else {
  349. contractList.value = [];
  350. }
  351. };
  352. const clickAdd = () => {
  353. if (formData.data.payDetailList && formData.data.payDetailList.length > 0) {
  354. formData.data.payDetailList.push({
  355. purchaseId: "",
  356. money: undefined,
  357. remark: "",
  358. });
  359. } else {
  360. formData.data.payDetailList = [{ purchaseId: "", money: undefined, remark: "" }];
  361. }
  362. };
  363. const handleRemove = (index) => {
  364. formData.data.payDetailList.splice(index, 1);
  365. };
  366. const changeAccount = (val) => {
  367. if (val) {
  368. let data = accountList.value.filter((item) => item.value === val);
  369. if (data && data.length > 0) {
  370. formData.data.bankName = data[0].bankName;
  371. formData.data.accountOpening = data[0].accountOpening;
  372. formData.data.openingBank = data[0].openingBank;
  373. formData.data.interbankNumber = data[0].interbankNumber;
  374. }
  375. }
  376. };
  377. const changePurchaseId = (row) => {
  378. let data = contractList.value.filter((item) => item.value === row.purchaseId);
  379. if (data && data.length > 0) {
  380. row.amount = data[0].amount;
  381. row.sumPayMoney = data[0].sumPayMoney;
  382. } else {
  383. row.amount = "";
  384. row.sumPayMoney = "";
  385. }
  386. };
  387. const changeMoney = () => {
  388. let money = 0;
  389. for (let i = 0; i < formData.data.payDetailList.length; i++) {
  390. if (formData.data.payDetailList[i].money) {
  391. money = parseFloat(Number(money) + Number(formData.data.payDetailList[i].money)).toFixed(2);
  392. }
  393. }
  394. formData.data.amount = money;
  395. };
  396. const handleSubmit = async () => {
  397. let status = await submit.value.handleSubmit(() => {});
  398. if (status) {
  399. if (formData.data.payDetailList && formData.data.payDetailList.length > 0) {
  400. if (fileList.value && fileList.value.length > 0) {
  401. formData.data.fileList = fileList.value.map((item) => {
  402. return {
  403. id: item.raw.id,
  404. fileName: item.raw.fileName,
  405. fileUrl: item.raw.fileUrl,
  406. };
  407. });
  408. }
  409. return true;
  410. } else {
  411. ElMessage("请添加至少一条付款明细");
  412. }
  413. return false;
  414. }
  415. return status;
  416. };
  417. // 接收父组件的传值
  418. const props = defineProps({
  419. queryData: Object,
  420. });
  421. watch(
  422. props.queryData,
  423. () => {
  424. formOption.disabled = judgeStatus();
  425. if (props.queryData && (route.query.processType == 10 || route.query.processType == 20)) {
  426. for (var text in props.queryData) {
  427. formData.data[text] = props.queryData[text];
  428. }
  429. if (formData.data.fileList && formData.data.fileList.length > 0) {
  430. fileList.value = formData.data.fileList.map((item) => {
  431. return {
  432. raw: item,
  433. name: item.fileName,
  434. url: item.fileUrl,
  435. };
  436. });
  437. } else {
  438. fileList.value = [];
  439. }
  440. }
  441. },
  442. {
  443. deep: true,
  444. }
  445. );
  446. onMounted(async () => {
  447. if (props.queryData.supplyId) {
  448. formData.data.supplyId = props.queryData.supplyId;
  449. await changeSupply(formData.data.supplyId);
  450. if (props.queryData.ids) {
  451. let ids = props.queryData.ids.split(",");
  452. if (ids && ids.length > 0) {
  453. for (let i = 0; i < ids.length; i++) {
  454. if (contractList.value && contractList.value.length > 0) {
  455. let data = contractList.value.filter((item) => item.value === ids[i]);
  456. if (data && data.length > 0) {
  457. if (formData.data.payDetailList && formData.data.payDetailList.length > 0) {
  458. formData.data.payDetailList.push({
  459. purchaseId: ids[i],
  460. money: undefined,
  461. remark: "",
  462. });
  463. } else {
  464. formData.data.payDetailList = [{ purchaseId: ids[i], money: undefined, remark: "" }];
  465. }
  466. }
  467. }
  468. }
  469. if (formData.data.payDetailList && formData.data.payDetailList.length > 0) {
  470. for (let i = 0; i < formData.data.payDetailList.length; i++) {
  471. changePurchaseId(formData.data.payDetailList[i]);
  472. }
  473. }
  474. }
  475. }
  476. }
  477. });
  478. const getFormData = () => {
  479. return formData.data;
  480. };
  481. // 向父组件暴露
  482. defineExpose({
  483. getFormData,
  484. handleSubmit,
  485. });
  486. </script>
  487. <style lang="scss" scoped>
  488. ::v-deep(.el-input-number .el-input__inner) {
  489. text-align: left;
  490. }
  491. </style>