PriceSheet.vue 11 KB

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