add.vue 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582
  1. <template>
  2. <div class="form">
  3. <van-nav-bar :title="$t('salesContract.name')" :left-text="$t('common.back')" left-arrow @click-left="onClickLeft">
  4. </van-nav-bar>
  5. <testForm v-model="formData.data" :formOption="formOption" :formConfig="formConfig" :rules="rules" @onSubmit="onSubmit(20)"
  6. @otherBtnClick="onSubmit(10)" ref="formDom"></testForm>
  7. </div>
  8. </template>
  9. <script setup>
  10. import { ref, reactive, getCurrentInstance, onMounted } from "vue";
  11. import { showSuccessToast, showFailToast } from "vant";
  12. import { useRoute } from "vue-router";
  13. import testForm from "@/components/testForm/index.vue";
  14. const proxy = getCurrentInstance().proxy;
  15. const route = useRoute();
  16. const formDom = ref(null);
  17. const formData = reactive({
  18. data: {
  19. salesContractDetailsList: [],
  20. },
  21. });
  22. const rules = {
  23. customerId: [
  24. {
  25. required: true,
  26. message: proxy.t("salesContract.pleaseSelectTheCustomerName"),
  27. },
  28. ],
  29. deliveryDate: [
  30. {
  31. required: true,
  32. message: proxy.t("salesContract.pleaseSelectTheDeliveryDeadline"),
  33. },
  34. ],
  35. payMethod: [
  36. {
  37. required: true,
  38. message: proxy.t("salesContract.pleaseSelectThePaymentMethod"),
  39. },
  40. ],
  41. freightPayer: [
  42. {
  43. required: true,
  44. message: proxy.t("salesContract.PleaseSelectTheFreightPayer"),
  45. },
  46. ],
  47. productId: [
  48. {
  49. required: true,
  50. message: proxy.t("salesContract.pleaseSelectTheProductName"),
  51. },
  52. ],
  53. isCustomized: [
  54. {
  55. required: true,
  56. message: proxy.t("salesContract.pleaseSelectWhetherToCustomize"),
  57. },
  58. ],
  59. unitPrice: [
  60. {
  61. required: true,
  62. message: proxy.t("salesContract.pleaseEnterTheUnitPrice"),
  63. },
  64. ],
  65. quantity: [
  66. {
  67. required: true,
  68. message: proxy.t("salesContract.pleaseEnterTheQuantity"),
  69. },
  70. ],
  71. devUserId: [
  72. {
  73. required: true,
  74. message: "请选择研发负责人",
  75. },
  76. ],
  77. };
  78. const formOption = reactive({
  79. readonly: false, //用于控制整个表单是否只读
  80. disabled: false,
  81. labelAlign: "top",
  82. scroll: true,
  83. labelWidth: "62pk",
  84. hiddenSubmitBtn: false,
  85. otherBtn: true,
  86. otherBtnText: "暂存",
  87. btnConfig: {
  88. isNeed: true,
  89. prop: "salesContractDetailsList",
  90. plain: true,
  91. listTitle: proxy.t("salesContract.contractDetails"),
  92. listConfig: [
  93. {
  94. type: "picker",
  95. label: proxy.t("salesContract.productName"),
  96. prop: "productId",
  97. itemType: "onePicker",
  98. showPicker: false,
  99. readonly: false,
  100. fieldNames: {
  101. text: "label",
  102. value: "value",
  103. },
  104. data: [],
  105. isNeedSearch: true, //是否需要关键字过滤数据
  106. searchKeyword: "",
  107. onSearchData: (keyword) => {
  108. getProductData(keyword);
  109. },
  110. },
  111. {
  112. type: "picker",
  113. label: proxy.t("salesContract.whetherToCustomize"),
  114. prop: "isCustomized",
  115. itemType: "onePicker",
  116. showPicker: false,
  117. readonly: false,
  118. fieldNames: {
  119. text: "label",
  120. value: "value",
  121. },
  122. data: [
  123. {
  124. label: proxy.t("salesContract.yes"),
  125. value: "1",
  126. },
  127. {
  128. label: proxy.t("salesContract.no"),
  129. value: "0",
  130. },
  131. ],
  132. },
  133. {
  134. type: "input",
  135. itemType: "number",
  136. label: proxy.t("salesContract.unitPrice"),
  137. prop: "unitPrice",
  138. clearable: true,
  139. changeFn: (index, val) => {
  140. changeAmount(index);
  141. },
  142. },
  143. {
  144. type: "input",
  145. itemType: "digit",
  146. label: proxy.t("salesContract.quantity"),
  147. prop: "quantity",
  148. clearable: true,
  149. changeFn: (index, val) => {
  150. changeAmount(index);
  151. },
  152. },
  153. {
  154. type: "input",
  155. itemType: "number",
  156. label: proxy.t("salesContract.amountSubtotal"),
  157. prop: "total",
  158. placeholder: proxy.t(
  159. "salesContract.automaticallyCalculatedBasedOnUnitPriceAndQuantity"
  160. ),
  161. readonly: true,
  162. },
  163. {
  164. type: "input",
  165. itemType: "textarea",
  166. label: "备注",
  167. prop: "productRemark",
  168. },
  169. ],
  170. clickFn: () => {
  171. if (
  172. formData.data.salesContractDetailsList &&
  173. formData.data.salesContractDetailsList.length > 0
  174. ) {
  175. formData.data.salesContractDetailsList.push({
  176. productId: "",
  177. quantity: "",
  178. });
  179. } else {
  180. formData.data.salesContractDetailsList = [
  181. {
  182. productId: "",
  183. quantity: "",
  184. },
  185. ];
  186. }
  187. },
  188. },
  189. });
  190. const formConfig = reactive([
  191. {
  192. type: "picker",
  193. label: "卖方公司",
  194. prop: "sellCorporationId",
  195. itemType: "onePicker",
  196. showPicker: false,
  197. fieldNames: {
  198. text: "label",
  199. value: "value",
  200. },
  201. data: [],
  202. changeFn: (val, data) => {
  203. proxy.formChange(val, data, formData);
  204. changeSellId(val.selectedValues[0]);
  205. data.showPicker = false;
  206. },
  207. },
  208. {
  209. type: "input",
  210. itemType: "text",
  211. label: "国家",
  212. prop: "sellCountryName",
  213. },
  214. {
  215. type: "input",
  216. itemType: "text",
  217. label: "省",
  218. prop: "sellProvinceName",
  219. },
  220. {
  221. type: "input",
  222. itemType: "text",
  223. label: "城市",
  224. prop: "sellCityName",
  225. },
  226. {
  227. type: "input",
  228. itemType: "textarea",
  229. label: "详细地址",
  230. prop: "sellAddress",
  231. },
  232. {
  233. type: "picker",
  234. label: "收款账号",
  235. prop: "shroffAccountId",
  236. itemType: "onePicker",
  237. showPicker: false,
  238. fieldNames: {
  239. text: "label",
  240. value: "value",
  241. },
  242. data: [],
  243. changeFn: (val, data) => {
  244. proxy.formChange(val, data, formData);
  245. changeShroffAccount(val.selectedValues[0]);
  246. data.showPicker = false;
  247. },
  248. },
  249. {
  250. type: "input",
  251. itemType: "text",
  252. label: "账户名",
  253. prop: "sellAccountName",
  254. },
  255. {
  256. type: "input",
  257. itemType: "text",
  258. label: "开户行",
  259. prop: "sellOpeningBank",
  260. },
  261. {
  262. type: "input",
  263. itemType: "text",
  264. label: "账号",
  265. prop: "sellAccountOpening",
  266. },
  267. {
  268. type: "input",
  269. itemType: "text",
  270. label: "银行号",
  271. prop: "sellInterbankNumber",
  272. },
  273. {
  274. type: "picker",
  275. label: proxy.t("salesContract.customerName"),
  276. prop: "customerId",
  277. itemType: "onePicker",
  278. showPicker: false,
  279. fieldNames: {
  280. text: "label",
  281. value: "value",
  282. },
  283. data: [],
  284. isNeedSearch: true, //是否需要关键字过滤数据
  285. searchKeyword: "",
  286. onSearchData: (keyword) => {
  287. getCustomerData(keyword);
  288. },
  289. },
  290. {
  291. type: "picker",
  292. label: proxy.t("salesContract.deliveryDeadline"),
  293. prop: "deliveryDate",
  294. itemType: "datePicker",
  295. showPicker: false,
  296. split: "-",
  297. columnsType: ["year", "month", "day"],
  298. },
  299. {
  300. type: "picker",
  301. label: proxy.t("salesContract.paymentMethod"),
  302. prop: "payMethod",
  303. itemType: "onePicker",
  304. showPicker: false,
  305. fieldNames: {
  306. text: "label",
  307. value: "value",
  308. },
  309. data: [],
  310. },
  311. {
  312. type: "picker",
  313. label: proxy.t("salesContract.freightPayer"),
  314. prop: "freightPayer",
  315. itemType: "onePicker",
  316. showPicker: false,
  317. fieldNames: {
  318. text: "label",
  319. value: "value",
  320. },
  321. data: [
  322. {
  323. label: proxy.t("salesContract.partyA"),
  324. value: "0",
  325. },
  326. {
  327. label: proxy.t("salesContract.partyB"),
  328. value: "1",
  329. },
  330. ],
  331. },
  332. {
  333. type: "input",
  334. itemType: "textarea",
  335. label: "交货期限备注",
  336. prop: "deliveryDateRemark",
  337. },
  338. {
  339. type: "input",
  340. itemType: "textarea",
  341. label: "付款方式备注",
  342. prop: "payMethodRemark",
  343. },
  344. {
  345. type: "input",
  346. itemType: "textarea",
  347. label: proxy.t("salesContract.remarks"),
  348. prop: "remark",
  349. },
  350. {
  351. type: "input",
  352. itemType: "number",
  353. label: proxy.t("salesContract.contractTotalAmount"),
  354. prop: "contractAmount",
  355. readonly: true,
  356. },
  357. {
  358. type: "picker",
  359. label: "研发负责人",
  360. prop: "devUserId",
  361. itemType: "onePicker",
  362. showPicker: false,
  363. fieldNames: {
  364. text: "label",
  365. value: "value",
  366. },
  367. data: [],
  368. },
  369. ]);
  370. const onClickLeft = () => history.back();
  371. const fundsPaymentMethod = ref([]);
  372. const customerData = ref([]);
  373. const accountList = ref([]);
  374. const corporationList = ref([]);
  375. const productData = ref([]);
  376. const getDict = () => {
  377. proxy.getDictOne(["funds_payment_method"]).then((res) => {
  378. fundsPaymentMethod.value = res["funds_payment_method"].data.map((x) => ({
  379. label: x.dictValue,
  380. value: x.dictKey,
  381. }));
  382. formConfig[12].data = fundsPaymentMethod.value;
  383. });
  384. proxy.post("/customer/page", { pageNum: 1, pageSize: 9999 }).then((res) => {
  385. customerData.value = res.data.rows.map((x) => ({
  386. label: x.name,
  387. value: x.id,
  388. }));
  389. formConfig[10].data = customerData.value;
  390. });
  391. proxy
  392. .post("/productInfo/page", { pageNum: 1, pageSize: 9999, definition: "1" })
  393. .then((res) => {
  394. productData.value = res.data.rows.map((x) => ({
  395. label: x.name + ` (${x.spec})`,
  396. value: x.id,
  397. }));
  398. formOption.btnConfig.listConfig[0].data = productData.value;
  399. });
  400. proxy
  401. .post("/accountManagement/page", { pageNum: 1, pageSize: 999 })
  402. .then((res) => {
  403. accountList.value = res.data.rows.map((item) => {
  404. return {
  405. ...item,
  406. label: item.alias,
  407. value: item.id,
  408. };
  409. });
  410. formConfig[5].data = accountList.value;
  411. });
  412. proxy.post("/corporation/page", { pageNum: 1, pageSize: 999 }).then((res) => {
  413. corporationList.value = res.data.rows.map((item) => {
  414. return {
  415. ...item,
  416. label: item.name,
  417. value: item.id,
  418. };
  419. });
  420. formConfig[0].data = corporationList.value;
  421. });
  422. proxy
  423. .post("/system/user/getUserList", {
  424. pageNum: 1,
  425. pageSize: 9999,
  426. roleKey: "dev",
  427. })
  428. .then((res) => {
  429. formConfig[18].data = res.data.map((item) => {
  430. return {
  431. ...item,
  432. label: item.nickName,
  433. value: item.userId,
  434. };
  435. });
  436. });
  437. };
  438. const getProductData = (keyword) => {
  439. proxy
  440. .post("/productInfo/page", { keyword, definition: "1", pageSize: 9999 })
  441. .then((res) => {
  442. productData.value = res.data.rows.map((x) => ({
  443. label: x.name + ` (${x.spec})`,
  444. value: x.id,
  445. }));
  446. formOption.btnConfig.listConfig[0].data = productData.value;
  447. });
  448. };
  449. const getCustomerData = (keyword) => {
  450. proxy.post("/customer/page", { keyword, pageSize: 9999 }).then((res) => {
  451. customerData.value = res.data.rows.map((x) => ({
  452. label: x.name,
  453. value: x.id,
  454. }));
  455. formConfig[10].data = customerData.value;
  456. });
  457. };
  458. const getDetails = (id) => {
  459. proxy.post("/salesContract/detail", { id }).then((res) => {
  460. if (res.data && res.data.contractDetailsList.length > 0) {
  461. res.data.salesContractDetailsList = res.data.contractDetailsList;
  462. } else {
  463. res.data.salesContractDetailsList = [];
  464. }
  465. res.data.deliveryDate = res.data.deliveryDate.slice(0, 10);
  466. formData.data = res.data;
  467. changeAmount();
  468. setTimeout(() => {
  469. formDom.value.formDataListShowLabelOne();
  470. }, 1000);
  471. });
  472. };
  473. onMounted(() => {
  474. getDict();
  475. if (route.query.id) {
  476. getDetails(route.query.id);
  477. if (route.query.status != 0) {
  478. formOption.readonly = true; //全部只读
  479. formOption.hiddenSubmitBtn = true; //隐藏提交按钮
  480. formOption.otherBtn = false; //隐藏其他按钮操作
  481. formOption.btnConfig.isNeed = false;
  482. }
  483. }
  484. });
  485. const onSubmit = (type) => {
  486. if (formData.data.salesContractDetailsList.length > 0) {
  487. if (type == 10) {
  488. proxy.post("/salesContract/add", formData.data).then(
  489. () => {
  490. showSuccessToast("暂存成功");
  491. setTimeout(() => {
  492. onClickLeft();
  493. }, 500);
  494. },
  495. (err) => {
  496. return showFailToast(err.message);
  497. }
  498. );
  499. } else {
  500. proxy
  501. .post("/flowProcess/initiate", {
  502. flowKey: "jxst_sales_contract_flow",
  503. data: formData.data,
  504. })
  505. .then(
  506. () => {
  507. showSuccessToast(proxy.t("common.operationSuccessful"));
  508. setTimeout(() => {
  509. onClickLeft();
  510. }, 500);
  511. },
  512. (err) => {
  513. return showFailToast(err.message);
  514. }
  515. );
  516. }
  517. } else {
  518. return showFailToast(proxy.t("salesContract.pleaseAddContractDetails"));
  519. }
  520. };
  521. const changeSellId = (val) => {
  522. if (val) {
  523. proxy.post("/corporation/detail", { id: val }).then((res) => {
  524. let detailCorporation = res.data;
  525. if (detailCorporation.countryName) {
  526. formData.data.sellCountryName = detailCorporation.countryName;
  527. }
  528. if (detailCorporation.provinceName) {
  529. formData.data.sellProvinceName = detailCorporation.provinceName;
  530. }
  531. if (detailCorporation.cityName) {
  532. formData.data.sellCityName = detailCorporation.cityName;
  533. }
  534. if (detailCorporation.address) {
  535. formData.data.sellAddress = detailCorporation.address;
  536. }
  537. });
  538. }
  539. };
  540. const changeShroffAccount = (val) => {
  541. if (val) {
  542. let data = accountList.value.filter((item) => item.value === val);
  543. if (data && data.length > 0) {
  544. formData.data.sellAccountName = data[0].name;
  545. formData.data.sellOpeningBank = data[0].openingBank;
  546. formData.data.sellInterbankNumber = data[0].interbankNumber;
  547. formData.data.sellAccountOpening = data[0].accountOpening;
  548. }
  549. }
  550. };
  551. const changeAmount = (index) => {
  552. let total = 0;
  553. for (let i = 0; i < formData.data.salesContractDetailsList.length; i++) {
  554. const element = formData.data.salesContractDetailsList[i];
  555. if (element.unitPrice && element.quantity) {
  556. element.total = parseFloat(element.unitPrice * element.quantity).toFixed(
  557. 2
  558. );
  559. total += Number(element.total);
  560. }
  561. }
  562. if (total) {
  563. formData.data.contractAmount = total.toFixed(2);
  564. }
  565. };
  566. </script>
  567. <style lang="scss" scoped>
  568. .form {
  569. margin-bottom: 60px;
  570. }
  571. </style>