PurchasePayment.vue 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712
  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 #supplyId>
  5. <div style="width: 100%">
  6. <el-form-item prop="supplyId" label="供应商" class="margin-b-0">
  7. <el-select v-model="formData.data.supplyId" filterable remote reserve-keyword placeholder="请输入关键字" remote-show-suffix
  8. :remote-method="remoteMethod" :loading="loadingSearch" @input="remoteMethod" style="width: 100%" @change="changeSupply" v-if="
  9. [30].includes(route.query.processType) ||
  10. !route.query.processType
  11. ">
  12. <el-option v-for="item in supplierList" :key="item.value" :label="item.label" :value="item.value" />
  13. </el-select>
  14. <el-select v-model="formData.data.supplyName" disabled v-else style="width: 100%">
  15. </el-select>
  16. </el-form-item>
  17. </div>
  18. </template>
  19. <template #payDetailList>
  20. <div style="width: 100%">
  21. <el-button type="primary" @click="clickAdd()" v-if="!judgeStatus()">添加行</el-button>
  22. <el-table :data="formData.data.payDetailList" style="width: 100%; margin-top: 16px">
  23. <el-table-column label="采购订单" width="220">
  24. <template #default="{ row, $index }">
  25. <div style="width: 100%">
  26. <el-form-item :prop="'payDetailList.' + $index + '.purchaseId'" :rules="rules.purchaseId" :inline-message="true" class="margin-b-0">
  27. <el-select v-model="row.purchaseId" placeholder="请选择采购订单" filterable style="width: 100%" @change="changePurchaseId(row, true)">
  28. <el-option v-for="item in contractList" :key="item.value" :label="item.label" :value="item.value" />
  29. </el-select>
  30. </el-form-item>
  31. </div>
  32. </template>
  33. </el-table-column>
  34. <el-table-column prop="amount" label="订单金额" width="140" />
  35. <el-table-column prop="sumPayMoney" label="已付款金额" width="140" />
  36. <el-table-column prop="sumInvoiceMoney" label="已收发票金额" width="140" />
  37. <el-table-column label="付款金额" width="180">
  38. <template #default="{ row, $index }">
  39. <div style="width: 100%">
  40. <el-form-item :prop="'payDetailList.' + $index + '.money'" :rules="rules.money" :inline-message="true" class="margin-b-0">
  41. <el-input-number onmousewheel="return false;" v-model="row.money" placeholder="请输入金额" style="width: 100%" :precision="2"
  42. :controls="false" :min="0" @change="changeMoney()" />
  43. </el-form-item>
  44. </div>
  45. </template>
  46. </el-table-column>
  47. <el-table-column label="款项说明">
  48. <template #default="{ row, $index }">
  49. <div style="width: 100%">
  50. <el-form-item :prop="'payDetailList.' + $index + '.remark'" :rules="rules.remark" :inline-message="true" class="margin-b-0">
  51. <el-input v-model="row.remark" placeholder="请输入款项说明" style="width: 100%" />
  52. </el-form-item>
  53. </div>
  54. </template>
  55. </el-table-column>
  56. <el-table-column label="操作" width="80" v-if="!judgeStatus()">
  57. <template #default="{ row, $index }">
  58. <el-button type="primary" link @click="handleRemove($index)">删除</el-button>
  59. </template>
  60. </el-table-column>
  61. </el-table>
  62. <br />
  63. </div>
  64. </template>
  65. </byForm>
  66. </div>
  67. </template>
  68. <script setup>
  69. import byForm from "@/components/byForm/index";
  70. import { ElMessage } from "element-plus";
  71. import useUserStore from "@/store/modules/user";
  72. import { useRoute } from "vue-router";
  73. import { async } from "@antv/x6/lib/registry/marker/async";
  74. const route = useRoute();
  75. const { proxy } = getCurrentInstance();
  76. const invoiceType = computed(
  77. () => proxy.useUserStore().allDict["invoice_type"]
  78. );
  79. const fundsPaymentMethod = computed(
  80. () => proxy.useUserStore().allDict["funds_payment_method"]
  81. );
  82. const payMethod = computed(() => proxy.useUserStore().allDict["pay_method"]);
  83. const supplierList = ref([]);
  84. const accountList = ref([]);
  85. const contractList = ref([]);
  86. let formData = reactive({
  87. data: {
  88. supplyId: "",
  89. amount: "",
  90. invoiceType: "",
  91. remark: "",
  92. deadline: "",
  93. receiptsNum: null,
  94. payType: "",
  95. currency: "",
  96. accountManagementId: "",
  97. userName: "",
  98. payDetailList: [],
  99. fileList: [],
  100. advanceCode: "",
  101. type: "",
  102. taxRate: null,
  103. },
  104. });
  105. const submit = ref(null);
  106. const judgeStatus = () => {
  107. if (route.query.processType == 20 || route.query.processType == 10) {
  108. return true;
  109. }
  110. if (props.queryData.recordList && props.queryData.recordList.length > 0) {
  111. let data = props.queryData.recordList.filter(
  112. (item) => item.status === 2 && item.nodeType !== 1
  113. );
  114. if (data && data.length > 0) {
  115. return true;
  116. }
  117. }
  118. return false;
  119. };
  120. const formOption = reactive({
  121. inline: true,
  122. labelWidth: 100,
  123. itemWidth: 100,
  124. disabled: false,
  125. });
  126. const formConfig = computed(() => {
  127. return [
  128. {
  129. type: "title",
  130. title: "基础信息",
  131. label: "",
  132. },
  133. {
  134. type: "slot",
  135. slotName: "supplyId",
  136. label: "",
  137. itemWidth: 33.33,
  138. },
  139. {
  140. type: "date",
  141. prop: "deadline",
  142. itemType: "date",
  143. label: "付款期限",
  144. itemWidth: 33.33,
  145. },
  146. {
  147. type: "select",
  148. label: "付款类型",
  149. prop: "type",
  150. data: payMethod.value,
  151. itemWidth: 33.33,
  152. style: "width: 100%",
  153. fn: () => {
  154. formData.data.advanceCode = "";
  155. },
  156. },
  157. // {
  158. // type: "select",
  159. // label: "预付款单号",
  160. // prop: "advanceCode",
  161. // data: advanceCode.value,
  162. // itemWidth: 34,
  163. // style: "width: 100%",
  164. // isShow: formData.data.type == "1",
  165. // },
  166. {
  167. type: "input",
  168. prop: "remark",
  169. label: "付款说明",
  170. itemType: "textarea",
  171. },
  172. {
  173. type: "treeSelect",
  174. prop: "companyId",
  175. label: "业务公司",
  176. data: proxy.useUserStore().allDict["tree_company_data"],
  177. propsTreeLabel: "deptName",
  178. propsTreeValue: "deptId",
  179. itemWidth: 33.33,
  180. disabled: true,
  181. },
  182. {
  183. type: "number",
  184. prop: "receiptsNum",
  185. label: "单据数量",
  186. precision: 0,
  187. min: 0,
  188. controls: false,
  189. itemWidth: 33.33,
  190. },
  191. {
  192. type: "select",
  193. label: "发票类型",
  194. prop: "invoiceType",
  195. data: invoiceType.value,
  196. itemWidth: 33,
  197. style: "width: 100%",
  198. fn: (val) => {
  199. if (val == "1") {
  200. formData.data.taxRate = 13;
  201. } else if (val == "2") {
  202. formData.data.taxRate = 6;
  203. } else {
  204. formData.data.taxRate = undefined;
  205. }
  206. },
  207. },
  208. {
  209. type: "number",
  210. prop: "taxRate",
  211. label: "税率 (%)",
  212. precision: 2,
  213. min: 0,
  214. controls: false,
  215. itemWidth: 33.33,
  216. isShow:
  217. formData.data.invoiceType == "1" || formData.data.invoiceType == "2",
  218. },
  219. {
  220. type: "upload",
  221. listType: "text",
  222. accept: "",
  223. prop: "fileList",
  224. label: "上传附件",
  225. },
  226. {
  227. type: "title",
  228. title: "付款明细",
  229. haveLine: true,
  230. },
  231. {
  232. type: "slot",
  233. prop: "payDetailList",
  234. slotName: "payDetailList",
  235. label: "",
  236. },
  237. {
  238. type: "input",
  239. prop: "amount",
  240. label: "付款总额",
  241. required: true,
  242. itemType: "text",
  243. disabled: true,
  244. itemWidth: 33.33,
  245. },
  246. {
  247. type: "title",
  248. title: "收款信息",
  249. haveLine: true,
  250. },
  251. {
  252. type: "select",
  253. label: "付款方式",
  254. prop: "payType",
  255. data: fundsPaymentMethod.value,
  256. itemWidth: 50,
  257. },
  258. {
  259. type: "select",
  260. label: "付款账户",
  261. prop: "accountManagementId",
  262. data: accountList.value,
  263. itemWidth: 50,
  264. fn: (val) => {
  265. changeAccount(val);
  266. },
  267. },
  268. {
  269. type: "input",
  270. prop: "name",
  271. label: "户名",
  272. required: true,
  273. itemType: "text",
  274. itemWidth: 50,
  275. },
  276. {
  277. type: "input",
  278. prop: "accountOpening",
  279. label: "银行账号",
  280. required: true,
  281. itemType: "text",
  282. itemWidth: 50,
  283. },
  284. {
  285. type: "input",
  286. prop: "openingBank",
  287. label: "开户银行",
  288. required: true,
  289. itemType: "text",
  290. itemWidth: 50,
  291. },
  292. {
  293. type: "input",
  294. prop: "interbankNumber",
  295. label: "联行号",
  296. required: true,
  297. itemType: "text",
  298. itemWidth: 50,
  299. },
  300. ];
  301. });
  302. const rules = ref({
  303. supplyId: [{ required: true, message: "请选择供应商", trigger: "change" }],
  304. invoiceType: [
  305. { required: true, message: "请选择发票类型", trigger: "change" },
  306. ],
  307. payType: [{ required: true, message: "请选择付款方式", trigger: "change" }],
  308. // accountManagementId: [{ required: true, message: "请选择付款账户", trigger: "change" }],
  309. purchaseId: [
  310. { required: true, message: "请选择采购订单", trigger: "change" },
  311. ],
  312. money: [{ required: true, message: "请输入付款金额", trigger: "blur" }],
  313. name: [{ required: true, message: "请输入户名", trigger: "blur" }],
  314. advanceCode: [
  315. { required: true, message: "请选择预付款单号", trigger: "change" },
  316. ],
  317. type: [{ required: true, message: "请选择付款类型", trigger: "change" }],
  318. taxRate: [{ required: true, message: "请输入税率", trigger: "blur" }],
  319. companyId: [{ required: true, message: "请选择业务公司", trigger: "change" }],
  320. });
  321. const getDict = () => {
  322. proxy.post("/supplierInfo/page", { pageNum: 1, pageSize: 50 }).then((res) => {
  323. if (res.rows && res.rows.length > 0) {
  324. supplierList.value = res.rows.map((item) => {
  325. return {
  326. ...item,
  327. label: item.name,
  328. value: item.id,
  329. };
  330. });
  331. }
  332. });
  333. proxy
  334. .post("/accountManagement/page", { pageNum: 1, pageSize: 999 })
  335. .then((res) => {
  336. accountList.value = res.rows.map((item) => {
  337. return {
  338. bankName: item.name,
  339. accountOpening: item.accountOpening,
  340. openingBank: item.openingBank,
  341. interbankNumber: item.interbankNumber,
  342. label: item.alias,
  343. value: item.id,
  344. };
  345. });
  346. });
  347. };
  348. getDict();
  349. const changeSupply = async (val) => {
  350. if (val) {
  351. await proxy
  352. .get("/ehsdPurchase/getListBySupplyId", { supplyId: val })
  353. .then((res) => {
  354. if (res.data && res.data.length > 0) {
  355. contractList.value = res.data.map((item) => {
  356. return {
  357. value: item.id,
  358. label: item.code,
  359. payableAmount: item.payableAmount,
  360. sumPayMoney: item.sumPayMoney,
  361. sumInvoiceMoney: item.sumInvoiceMoney,
  362. };
  363. });
  364. } else {
  365. contractList.value = [];
  366. }
  367. });
  368. } else {
  369. contractList.value = [];
  370. }
  371. formData.data.payDetailList = [];
  372. getDecisionAids();
  373. };
  374. const clickAdd = () => {
  375. if (formData.data.payDetailList && formData.data.payDetailList.length > 0) {
  376. formData.data.payDetailList.push({
  377. purchaseId: "",
  378. money: undefined,
  379. remark: "",
  380. });
  381. } else {
  382. formData.data.payDetailList = [
  383. { purchaseId: "", money: undefined, remark: "" },
  384. ];
  385. }
  386. };
  387. const handleRemove = (index) => {
  388. formData.data.payDetailList.splice(index, 1);
  389. getDecisionAids();
  390. changeMoney();
  391. };
  392. const changeAccount = (val) => {
  393. if (val) {
  394. let data = accountList.value.filter((item) => item.value === val);
  395. if (data && data.length > 0) {
  396. formData.data.name = data[0].bankName;
  397. formData.data.accountOpening = data[0].accountOpening;
  398. formData.data.openingBank = data[0].openingBank;
  399. formData.data.interbankNumber = data[0].interbankNumber;
  400. }
  401. }
  402. };
  403. const changePurchaseId = (row, status) => {
  404. let data = contractList.value.filter((item) => item.value === row.purchaseId);
  405. console.log(data, "sss");
  406. if (data && data.length > 0) {
  407. row.amount = data[0].payableAmount;
  408. row.sumPayMoney = data[0].sumPayMoney;
  409. row.sumInvoiceMoney = data[0].sumInvoiceMoney;
  410. } else {
  411. row.amount = "";
  412. row.sumPayMoney = "";
  413. row.sumInvoiceMoney = "";
  414. }
  415. if (status) {
  416. getDecisionAids();
  417. }
  418. };
  419. const changeMoney = () => {
  420. let money = 0;
  421. for (let i = 0; i < formData.data.payDetailList.length; i++) {
  422. if (formData.data.payDetailList[i].money) {
  423. money = parseFloat(
  424. Number(money) + Number(formData.data.payDetailList[i].money)
  425. ).toFixed(2);
  426. }
  427. }
  428. formData.data.amount = money;
  429. };
  430. const handleSubmit = async () => {
  431. let status = await submit.value.handleSubmit(() => {});
  432. if (status) {
  433. if (formData.data.payDetailList && formData.data.payDetailList.length > 0) {
  434. return true;
  435. } else {
  436. ElMessage("请添加至少一条付款明细");
  437. }
  438. return false;
  439. }
  440. return status;
  441. };
  442. // 接收父组件的传值
  443. const props = defineProps({
  444. queryData: Object,
  445. });
  446. onMounted(async () => {
  447. if (props.queryData.supplyIdTwo) {
  448. formData.data.supplyIdTwo = props.queryData.supplyIdTwo;
  449. await changeSupply(formData.data.supplyIdTwo);
  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(
  456. (item) => item.value === ids[i]
  457. );
  458. if (data && data.length > 0) {
  459. if (
  460. formData.data.payDetailList &&
  461. formData.data.payDetailList.length > 0
  462. ) {
  463. formData.data.payDetailList.push({
  464. purchaseId: ids[i],
  465. money: undefined,
  466. remark: "",
  467. });
  468. } else {
  469. formData.data.payDetailList = [
  470. { purchaseId: ids[i], money: undefined, remark: "" },
  471. ];
  472. }
  473. }
  474. }
  475. }
  476. if (
  477. formData.data.payDetailList &&
  478. formData.data.payDetailList.length > 0
  479. ) {
  480. for (let i = 0; i < formData.data.payDetailList.length; i++) {
  481. changePurchaseId(formData.data.payDetailList[i]);
  482. }
  483. getDecisionAids();
  484. }
  485. }
  486. }
  487. }
  488. formOption.disabled = judgeStatus();
  489. if (route.query && route.query.businessId) {
  490. proxy
  491. .post("/pay/detail", { id: route.query.businessId })
  492. .then(async (res) => {
  493. if (res.supplyId) {
  494. await changeSupply(res.supplyId);
  495. }
  496. res.payDetailList = res.payDetailVoList;
  497. for (const key in res) {
  498. formData.data[key] = res[key];
  499. }
  500. formData.data.fileList = [];
  501. if (
  502. formData.data.payDetailList &&
  503. formData.data.payDetailList.length > 0
  504. ) {
  505. for (let i = 0; i < formData.data.payDetailList.length; i++) {
  506. changePurchaseId(formData.data.payDetailList[i]);
  507. }
  508. getDecisionAids();
  509. }
  510. proxy
  511. .post("/fileInfo/getList", {
  512. businessIdList: [route.query.businessId],
  513. })
  514. .then((fileObj) => {
  515. if (
  516. fileObj[route.query.businessId] &&
  517. fileObj[route.query.businessId].length > 0
  518. ) {
  519. formData.data.fileList = fileObj[route.query.businessId].map(
  520. (x) => ({
  521. ...x,
  522. name: x.fileName,
  523. url: x.fileUrl,
  524. })
  525. );
  526. }
  527. });
  528. });
  529. }
  530. formData.data.companyId = proxy.useUserStore().user.companyId;
  531. });
  532. const getFormData = () => {
  533. return proxy.deepClone(formData.data);
  534. };
  535. // 向父组件暴露
  536. defineExpose({
  537. getFormData,
  538. handleSubmit,
  539. });
  540. let auxiliaryData = ref([
  541. {
  542. label: "关联销售订单",
  543. data: [],
  544. },
  545. {
  546. label: "到货数据",
  547. data: [],
  548. },
  549. {
  550. label: "质检数据",
  551. data: [],
  552. },
  553. ]);
  554. const emit = defineEmits(["auxiliaryChange"]);
  555. const getDecisionAids = () => {
  556. return;
  557. let data = {
  558. purchaseIdList: [],
  559. };
  560. if (formData.data.payDetailList && formData.data.payDetailList.length > 0) {
  561. data.purchaseIdList = formData.data.payDetailList.map(
  562. (item) => item.purchaseId
  563. );
  564. }
  565. proxy.post("/contract/payDecisionAid", data).then((res) => {
  566. if (res.contractList && res.contractList.length > 0) {
  567. auxiliaryData.value[0].data = res.contractList.map((item) => {
  568. return [
  569. {
  570. label: "合同编号",
  571. value: item.code,
  572. style: {
  573. color: "#0084FF",
  574. cursor: isHave.value ? "pointer" : "revert",
  575. },
  576. fn: isHave.value ? handlePushRoute : () => {},
  577. id: item.id,
  578. num: 1,
  579. },
  580. {
  581. label: "下单日期",
  582. value: item.createTime,
  583. id: item.id,
  584. num: 1,
  585. },
  586. ];
  587. });
  588. } else {
  589. auxiliaryData.value[0].data = [];
  590. }
  591. if (res.purchaseInfoList && res.purchaseInfoList.length > 0) {
  592. auxiliaryData.value[1].data = res.purchaseInfoList.map((item) => {
  593. return [
  594. {
  595. label: "合同编号",
  596. value: item.purchaseCode,
  597. style: {
  598. color: "#0084FF",
  599. cursor: isHaveOne.value ? "pointer" : "revert",
  600. },
  601. fn: isHaveOne.value ? handlePushRouteOne : () => {},
  602. id: item.purchaseId,
  603. num: 1,
  604. },
  605. {
  606. label: "物品编码",
  607. value: item.productCode,
  608. id: item.productId,
  609. num: 1,
  610. },
  611. {
  612. label: "物品名称",
  613. value: item.productName,
  614. id: item.productId,
  615. num: 1,
  616. },
  617. {
  618. label: "采购数量",
  619. value: item.purchaseQuantity,
  620. id: item.productId,
  621. num: 1,
  622. },
  623. {
  624. label: "到货数量",
  625. value: item.invoiceQuantity,
  626. id: item.productId,
  627. num: 1,
  628. },
  629. ];
  630. });
  631. auxiliaryData.value[2].data = res.purchaseInfoList.map((item) => {
  632. let odds = 0;
  633. if (item.invoiceQuantity && item.qualifiedCount) {
  634. odds = parseFloat(
  635. (Number(item.qualifiedCount) / Number(item.invoiceQuantity)) * 100
  636. ).toFixed(2);
  637. }
  638. return [
  639. {
  640. label: "合同编号",
  641. value: item.purchaseCode,
  642. style: {
  643. color: "#0084FF",
  644. cursor: isHaveOne.value ? "pointer" : "revert",
  645. },
  646. fn: isHaveOne.value ? handlePushRouteOne : () => {},
  647. id: item.purchaseId,
  648. num: 1,
  649. },
  650. {
  651. label: "物品编码",
  652. value: item.productCode,
  653. id: item.productId,
  654. num: 1,
  655. },
  656. {
  657. label: "物品名称",
  658. value: item.productName,
  659. id: item.productId,
  660. num: 1,
  661. },
  662. {
  663. label: "到货数量",
  664. value: item.invoiceQuantity,
  665. id: item.productId,
  666. num: 1,
  667. },
  668. {
  669. label: "合格率",
  670. value: odds + "%",
  671. id: item.productId,
  672. num: 1,
  673. },
  674. ];
  675. });
  676. } else {
  677. auxiliaryData.value[1].data = [];
  678. auxiliaryData.value[2].data = [];
  679. }
  680. let list = proxy.deepClone(auxiliaryData.value);
  681. if (!(list[0].data && list[0].data.length > 0)) {
  682. list.splice(0, 1);
  683. }
  684. emit("auxiliaryChange", list);
  685. });
  686. };
  687. const loadingSearch = ref(false);
  688. const remoteMethod = (keyword) => {
  689. if (keyword && typeof keyword === "string") {
  690. loadingSearch.value = true;
  691. proxy.post("/supplierInfo/page", { keyword }).then((res) => {
  692. supplierList.value = res.rows.map((x) => ({
  693. ...x,
  694. label: x.name,
  695. value: x.id,
  696. }));
  697. loadingSearch.value = false;
  698. });
  699. }
  700. return;
  701. };
  702. </script>
  703. <style lang="scss" scoped>
  704. </style>