PriceSheet.vue 44 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360
  1. <template>
  2. <div style="width: 100%; padding: 0px 15px">
  3. <byForm
  4. :formConfig="formConfig"
  5. :formOption="formOption"
  6. v-model="formData.data"
  7. :rules="rules"
  8. ref="submit"
  9. >
  10. <template #seller>
  11. <div style="width: 100%">
  12. <el-form-item prop="sellCorporationId">
  13. <el-select
  14. v-model="formData.data.sellCorporationId"
  15. style="width: 100%"
  16. disabled
  17. >
  18. <el-option
  19. v-for="item in corporationList"
  20. :key="item.value"
  21. :label="item.label"
  22. :value="item.value"
  23. />
  24. </el-select>
  25. </el-form-item>
  26. <el-row style="margin-top: 20px; width: 100%">
  27. <el-col :span="8">
  28. <el-form-item label="地址" prop="sellCountryName">
  29. <el-input
  30. v-model="formData.data.sellCountryName"
  31. placeholder="请输入国家"
  32. />
  33. </el-form-item>
  34. </el-col>
  35. <el-col :span="8">
  36. <el-form-item label=" " prop="sellProvinceName">
  37. <el-input
  38. v-model="formData.data.sellProvinceName"
  39. placeholder="请输入省/州"
  40. />
  41. </el-form-item>
  42. </el-col>
  43. <el-col :span="8">
  44. <el-form-item label=" " prop="sellCityName">
  45. <el-input
  46. v-model="formData.data.sellCityName"
  47. placeholder="请输入城市"
  48. />
  49. </el-form-item>
  50. </el-col>
  51. </el-row>
  52. <el-row style="margin-top: 20px; width: 100%">
  53. <el-col :span="24">
  54. <el-form-item prop="sellAddress">
  55. <el-input v-model="formData.data.sellAddress" type="textarea">
  56. </el-input>
  57. </el-form-item>
  58. </el-col>
  59. </el-row>
  60. <el-row style="margin-top: 20px; width: 100%">
  61. <el-col :span="8">
  62. <el-form-item label="联系人" prop="sellContactName">
  63. <el-input
  64. v-model="formData.data.sellContactName"
  65. placeholder="请输入联系人"
  66. />
  67. </el-form-item>
  68. </el-col>
  69. <el-col :span="16">
  70. <el-form-item label=" " prop="sellContactNumber">
  71. <el-input
  72. v-model="formData.data.sellContactNumber"
  73. placeholder="请输入联系人电话"
  74. />
  75. </el-form-item>
  76. </el-col>
  77. </el-row>
  78. </div>
  79. </template>
  80. <template #buyer>
  81. <div style="width: 100%">
  82. <div style="width: 100%">
  83. <el-form-item prop="buyCorporationId">
  84. <el-select
  85. v-model="formData.data.buyCorporationId"
  86. filterable
  87. style="width: 100%"
  88. @change="changeCustomer"
  89. >
  90. <el-option
  91. v-for="item in customerList"
  92. :key="item.value"
  93. :label="item.label"
  94. :value="item.value"
  95. />
  96. </el-select>
  97. </el-form-item>
  98. <el-row style="margin-top: 20px; width: 100%">
  99. <el-col :span="6">
  100. <el-form-item label="地址" prop="countryId">
  101. <el-select
  102. v-model="formData.data.countryId"
  103. placeholder="国家"
  104. filterable
  105. @change="(val) => getCityData(val, '20', true)"
  106. >
  107. <el-option
  108. v-for="item in countryData"
  109. :label="item.name"
  110. :value="item.id"
  111. >
  112. </el-option>
  113. </el-select>
  114. </el-form-item>
  115. </el-col>
  116. <el-col :span="6">
  117. <el-form-item label=" " prop="provinceName">
  118. <selectCity
  119. placeholder="省/洲"
  120. @change="(val) => getCityData(val, '30', true)"
  121. addressId="provinceId"
  122. addressName="provinceName"
  123. v-model="formData.data"
  124. :data="provinceData"
  125. >
  126. </selectCity>
  127. </el-form-item>
  128. </el-col>
  129. <el-col :span="6">
  130. <el-form-item label=" " prop="cityName">
  131. <selectCity
  132. placeholder="城市"
  133. addressId="cityId"
  134. addressName="cityName"
  135. v-model="formData.data"
  136. :data="cityData"
  137. >
  138. </selectCity>
  139. </el-form-item>
  140. </el-col>
  141. <el-col :span="6">
  142. <el-form-item label=" " prop="buyPostalCode">
  143. <el-input
  144. v-model="formData.data.buyPostalCode"
  145. placeholder="请输入邮编"
  146. />
  147. </el-form-item>
  148. </el-col>
  149. </el-row>
  150. <el-row style="margin-top: 20px; width: 100%">
  151. <el-col :span="24">
  152. <el-form-item prop="buyAddress">
  153. <el-input v-model="formData.data.buyAddress" type="textarea">
  154. </el-input>
  155. </el-form-item>
  156. </el-col>
  157. </el-row>
  158. <el-row style="margin-top: 20px; width: 100%">
  159. <el-col :span="8">
  160. <el-form-item label="联系人" prop="buyContactName">
  161. <el-autocomplete
  162. v-model="formData.data.buyContactName"
  163. :fetch-suggestions="querySearchPerson"
  164. clearable
  165. class="inline-input w-50"
  166. placeholder="请输入联系人"
  167. @select="handlePerson"
  168. >
  169. </el-autocomplete>
  170. </el-form-item>
  171. </el-col>
  172. <el-col :span="16">
  173. <el-form-item label=" " prop="buyContactNumber">
  174. <el-input
  175. v-model="formData.data.buyContactNumber"
  176. placeholder="请输入联系人电话"
  177. />
  178. </el-form-item>
  179. </el-col>
  180. </el-row>
  181. </div>
  182. </div>
  183. </template>
  184. <template #commodity>
  185. <div style="width: 100%">
  186. <el-button @click="openProduct = true">添加商品</el-button>
  187. <el-table
  188. :data="formData.data.quotationProductList"
  189. style="width: 100%; margin-top: 16px"
  190. >
  191. <el-table-column label="商品图片" width="80">
  192. <template #default="{ row }">
  193. <div v-if="row.fileUrl">
  194. <img
  195. :src="row.fileUrl"
  196. class="pic"
  197. @click="onPicture(row.fileUrl)"
  198. />
  199. </div>
  200. <div v-else></div>
  201. </template>
  202. </el-table-column>
  203. <el-table-column prop="code" label="商品编码" width="120" />
  204. <el-table-column prop="name" label="商品中文名" width="160" />
  205. <el-table-column label="商品英文名" min-width="200">
  206. <template #default="{ row, $index }">
  207. <div style="width: 100%">
  208. <el-form-item
  209. :prop="'quotationProductList.' + $index + '.productName'"
  210. :rules="rules.productName"
  211. :inline-message="true"
  212. >
  213. <el-input
  214. v-model="row.productName"
  215. placeholder="请输入商品英文名"
  216. />
  217. </el-form-item>
  218. </div>
  219. </template>
  220. </el-table-column>
  221. <el-table-column label="规格型号" width="180">
  222. <template #default="{ row, $index }">
  223. <div style="width: 100%">
  224. <el-form-item
  225. :prop="'quotationProductList.' + $index + '.productModel'"
  226. :inline-message="true"
  227. >
  228. <el-input
  229. v-model="row.productModel"
  230. placeholder="请输入规格型号"
  231. />
  232. </el-form-item>
  233. </div>
  234. </template>
  235. </el-table-column>
  236. <el-table-column
  237. prop="unit"
  238. label="单位"
  239. width="100"
  240. :formatter="(row) => dictValueLabel(row.unit, productUnit)"
  241. />
  242. <el-table-column label="数量" width="150">
  243. <template #default="{ row, $index }">
  244. <div style="width: 100%">
  245. <el-form-item
  246. :prop="'quotationProductList.' + $index + '.quantity'"
  247. :rules="rules.quantity"
  248. :inline-message="true"
  249. >
  250. <el-input-number
  251. onmousewheel="return false;"
  252. v-model="row.quantity"
  253. placeholder="请输入数量"
  254. style="width: 100%"
  255. :controls="false"
  256. :min="0"
  257. @change="
  258. () => {
  259. return calculationAmount(
  260. 'quotationProductList',
  261. $index,
  262. 'quantity'
  263. );
  264. }
  265. "
  266. />
  267. </el-form-item>
  268. </div>
  269. </template>
  270. </el-table-column>
  271. <el-table-column label="单价" width="160">
  272. <template #default="{ row, $index }">
  273. <div style="width: 100%">
  274. <el-form-item
  275. :prop="'quotationProductList.' + $index + '.price'"
  276. :rules="rules.price"
  277. :inline-message="true"
  278. >
  279. <el-input-number
  280. onmousewheel="return false;"
  281. v-model="row.price"
  282. placeholder="请输入单价"
  283. style="width: 100%"
  284. :controls="false"
  285. :min="0"
  286. @change="
  287. () => {
  288. return calculationAmount(
  289. 'quotationProductList',
  290. $index,
  291. 'price'
  292. );
  293. }
  294. "
  295. />
  296. </el-form-item>
  297. </div>
  298. </template>
  299. </el-table-column>
  300. <el-table-column prop="amount" label="金额" width="100" />
  301. <el-table-column
  302. align="center"
  303. label="操作"
  304. width="80"
  305. fixed="right"
  306. >
  307. <template #default="{ $index }">
  308. <el-button type="primary" link @click="handleRemove($index)"
  309. >删除</el-button
  310. >
  311. </template>
  312. </el-table-column>
  313. </el-table>
  314. </div>
  315. </template>
  316. <template #otherCharge>
  317. <div style="width: 100%">
  318. <el-button type="primary" @click="clickAdd()">添加行</el-button>
  319. <el-table
  320. :data="formData.data.quotationPayList"
  321. style="width: 100%; margin-top: 16px"
  322. >
  323. <el-table-column label="收费项目" width="220">
  324. <template #default="{ row, $index }">
  325. <div style="width: 100%">
  326. <el-form-item
  327. :prop="'quotationPayList.' + $index + '.payName'"
  328. :rules="rules.payName"
  329. :inline-message="true"
  330. >
  331. <el-autocomplete
  332. v-model="row.payName"
  333. :fetch-suggestions="querySearch"
  334. clearable
  335. class="inline-input w-50"
  336. placeholder="请输入收费项目"
  337. />
  338. </el-form-item>
  339. </div>
  340. </template>
  341. </el-table-column>
  342. <el-table-column label="金额" width="180">
  343. <template #default="{ row, $index }">
  344. <div style="width: 100%">
  345. <el-form-item
  346. :prop="'quotationPayList.' + $index + '.amount'"
  347. :rules="rules.amount"
  348. :inline-message="true"
  349. >
  350. <el-input-number
  351. onmousewheel="return false;"
  352. v-model="row.amount"
  353. placeholder="请输入金额"
  354. style="width: 100%"
  355. :controls="false"
  356. :min="0"
  357. @change="
  358. () => {
  359. return totalAmount(
  360. 'quotationPayList',
  361. $index,
  362. 'amount'
  363. );
  364. }
  365. "
  366. />
  367. </el-form-item>
  368. </div>
  369. </template>
  370. </el-table-column>
  371. <el-table-column label="备注">
  372. <template #default="{ row, $index }">
  373. <div style="width: 100%">
  374. <el-form-item
  375. :prop="'quotationPayList.' + $index + '.remark'"
  376. >
  377. <el-input v-model="row.remark" placeholder="请输入备注" />
  378. </el-form-item>
  379. </div>
  380. </template>
  381. </el-table-column>
  382. <el-table-column label="操作" width="80" fixed="right">
  383. <template #default="{ row, $index }">
  384. <el-button type="primary" link @click="handleDelete($index)"
  385. >删除</el-button
  386. >
  387. </template>
  388. </el-table-column>
  389. </el-table>
  390. </div>
  391. </template>
  392. <template #offerMoney>
  393. <div style="width: 100%">
  394. <el-row style="margin-top: 20px; width: 100%">
  395. <el-col :span="4">
  396. <el-form-item label="币种" prop="currency">
  397. <el-select
  398. v-model="formData.data.currency"
  399. placeholder="请选择币种"
  400. style="width: 100%"
  401. >
  402. <el-option
  403. v-for="item in accountCurrency"
  404. :key="item.value"
  405. :label="item.label"
  406. :value="item.value"
  407. />
  408. </el-select>
  409. </el-form-item>
  410. </el-col>
  411. <el-col :span="6">
  412. <el-form-item label="合同总金额" prop="amount">
  413. <el-input
  414. v-model="formData.data.amount"
  415. placeholder="合同总金额"
  416. disabled
  417. />
  418. </el-form-item>
  419. </el-col>
  420. <el-col :span="4">
  421. <el-form-item label="报价有效期 (天)" prop="effective">
  422. <el-input-number
  423. onmousewheel="return false;"
  424. v-model="formData.data.effective"
  425. placeholder="请输入有效期"
  426. style="width: 100%"
  427. :precision="0"
  428. :controls="false"
  429. :min="0"
  430. />
  431. </el-form-item>
  432. </el-col>
  433. </el-row>
  434. <el-row style="margin-top: 20px; width: 100%">
  435. <el-col :span="7">
  436. <el-form-item label="付款方式" prop="paymentMethod">
  437. <el-select
  438. v-model="formData.data.paymentMethod"
  439. placeholder="请选择付款方式"
  440. style="width: 100%"
  441. >
  442. <el-option
  443. v-for="item in fundsPaymentMethod"
  444. :key="item.value"
  445. :label="item.label"
  446. :value="item.value"
  447. />
  448. </el-select>
  449. </el-form-item>
  450. </el-col>
  451. <el-col :span="7">
  452. <el-form-item label="预付比例 (%)" prop="advanceRatio">
  453. <el-input-number
  454. onmousewheel="return false;"
  455. v-model="formData.data.advanceRatio"
  456. placeholder="请输入预付比例"
  457. style="width: 100%"
  458. :precision="2"
  459. :controls="false"
  460. :min="0"
  461. :max="100"
  462. />
  463. </el-form-item>
  464. </el-col>
  465. </el-row>
  466. </div>
  467. </template>
  468. <template #delivery>
  469. <div style="width: 100%">
  470. <el-row style="margin-top: 20px; width: 100%">
  471. <el-col :span="7">
  472. <el-form-item label="贸易方式" prop="tradeMethods">
  473. <el-select
  474. v-model="formData.data.tradeMethods"
  475. placeholder="请选择贸易方式"
  476. style="width: 100%"
  477. >
  478. <el-option
  479. v-for="item in tradeMethods"
  480. :key="item.value"
  481. :label="item.label"
  482. :value="item.value"
  483. />
  484. </el-select>
  485. </el-form-item>
  486. </el-col>
  487. </el-row>
  488. <el-row style="margin-top: 20px; width: 100%">
  489. <el-col :span="7">
  490. <el-form-item label="运输方式" prop="transportMethod">
  491. <el-select
  492. v-model="formData.data.transportMethod"
  493. placeholder="请选择运输方式"
  494. style="width: 100%"
  495. >
  496. <el-option
  497. v-for="item in shippingMethod"
  498. :key="item.value"
  499. :label="item.label"
  500. :value="item.value"
  501. />
  502. </el-select>
  503. </el-form-item>
  504. </el-col>
  505. <el-col :span="7">
  506. <el-form-item label="运输说明" prop="transportRemark">
  507. <el-input
  508. v-model="formData.data.transportRemark"
  509. placeholder="请输入运输说明"
  510. />
  511. </el-form-item>
  512. </el-col>
  513. </el-row>
  514. <el-row style="margin-top: 20px; width: 100%">
  515. <el-col :span="14">
  516. <el-form-item label="付款条件" prop="remark">
  517. <el-input
  518. v-model="formData.data.remark"
  519. :rows="2"
  520. type="textarea"
  521. placeholder="请输入付款条件"
  522. />
  523. </el-form-item>
  524. </el-col>
  525. </el-row>
  526. <el-row style="margin-top: 20px; width: 100%">
  527. <el-col :span="7">
  528. <el-form-item label="质保期 (天)" prop="warranty">
  529. <el-input-number
  530. onmousewheel="return false;"
  531. v-model="formData.data.warranty"
  532. placeholder="请输入质保期"
  533. style="width: 100%"
  534. :precision="0"
  535. :controls="false"
  536. :min="0"
  537. />
  538. </el-form-item>
  539. </el-col>
  540. </el-row>
  541. </div>
  542. </template>
  543. </byForm>
  544. <el-dialog
  545. v-if="openProduct"
  546. v-model="openProduct"
  547. title="选择商品"
  548. width="70%"
  549. append-to-body
  550. >
  551. <SelectGoods
  552. :selectList="acquireSelectList()"
  553. @cancel="openProduct = false"
  554. @pushGoods="pushGoods"
  555. ></SelectGoods>
  556. </el-dialog>
  557. </div>
  558. </template>
  559. <script setup>
  560. import byForm from "@/components/byForm/index";
  561. import SelectGoods from "@/components/product/SelectGoods";
  562. import { ElMessage } from "element-plus";
  563. import selectCity from "@/components/selectCity/index.vue";
  564. import { useRoute } from "vue-router";
  565. const route = useRoute();
  566. const { proxy } = getCurrentInstance();
  567. const accountCurrency = ref([]);
  568. const fundsPaymentMethod = ref([]);
  569. const tradeMethods = ref([]);
  570. const shippingMethod = ref([]);
  571. const productUnit = ref([]);
  572. const templateList = ref([]);
  573. const corporationList = ref([]);
  574. const customerList = ref([]);
  575. const countryData = ref([]);
  576. const provinceData = ref([]);
  577. const cityData = ref([]);
  578. const customerUserList = ref([]);
  579. const openProduct = ref(false);
  580. const formData = reactive({
  581. data: {
  582. amount: undefined,
  583. quotationProductList: [],
  584. quotationPayList: [],
  585. },
  586. });
  587. const submit = ref(null);
  588. const judgeStatus = () => {
  589. if (route.query.processType == 20 || route.query.processType == 10) {
  590. return true;
  591. }
  592. if (props.queryData.recordList && props.queryData.recordList.length > 0) {
  593. let data = props.queryData.recordList.filter(
  594. (item) => item.status === 2 && item.nodeType !== 1
  595. );
  596. if (data && data.length > 0) {
  597. return true;
  598. }
  599. }
  600. return false;
  601. };
  602. const formOption = reactive({
  603. inline: true,
  604. labelWidth: 100,
  605. itemWidth: 100,
  606. rules: [],
  607. disabled: false,
  608. });
  609. const formConfig = computed(() => {
  610. return [
  611. {
  612. type: "title",
  613. title: "合同模板",
  614. label: "",
  615. },
  616. {
  617. type: "select",
  618. label: "选择合同模板",
  619. prop: "contractTemplateId",
  620. data: templateList.value,
  621. fn: (val) => {
  622. changeTemplate(val);
  623. },
  624. },
  625. {
  626. type: "slot",
  627. slotName: "seller",
  628. label: "卖方信息",
  629. itemWidth: 50,
  630. },
  631. {
  632. type: "slot",
  633. slotName: "buyer",
  634. label: "买方信息",
  635. itemWidth: 50,
  636. },
  637. {
  638. type: "slot",
  639. slotName: "commodity",
  640. label: "商品信息",
  641. },
  642. {
  643. type: "slot",
  644. slotName: "otherCharge",
  645. label: "其他收费项目",
  646. },
  647. {
  648. type: "slot",
  649. slotName: "offerMoney",
  650. label: "报价金额",
  651. },
  652. {
  653. type: "slot",
  654. slotName: "delivery",
  655. label: "交付信息",
  656. },
  657. ];
  658. });
  659. const rules = ref({
  660. contractTemplateId: [
  661. { required: true, message: "请选择合同模板", trigger: "change" },
  662. ],
  663. buyCorporationId: [
  664. { required: true, message: "请选择公司", trigger: "change" },
  665. ],
  666. countryId: [{ required: true, message: "请选择国家", trigger: "change" }],
  667. sellAddress: [{ required: true, message: "请输入详细地址", trigger: "blur" }],
  668. buyAddress: [{ required: true, message: "请输入详细地址", trigger: "blur" }],
  669. buyContactName: [
  670. { required: true, message: "请输入联系人", trigger: ["change", "blur"] },
  671. ],
  672. buyContactNumber: [
  673. { required: true, message: "请输入联系电话", trigger: "blur" },
  674. ],
  675. productName: [
  676. { required: true, message: "请输入商品英文名", trigger: "blur" },
  677. ],
  678. productModel: [
  679. { required: true, message: "请输入规格型号", trigger: "blur" },
  680. ],
  681. quantity: [{ required: true, message: "请输入数量", trigger: "blur" }],
  682. price: [{ required: true, message: "请输入单价", trigger: "blur" }],
  683. amount: [{ required: true, message: "请输入金额", trigger: "blur" }],
  684. payName: [
  685. { required: true, message: "请输入收费项目", trigger: ["change", "blur"] },
  686. ],
  687. currency: [{ required: true, message: "请选择币种", trigger: "change" }],
  688. effective: [{ required: true, message: "请输入报价有效期", trigger: "blur" }],
  689. paymentMethod: [
  690. { required: true, message: "请选择付款方式", trigger: "change" },
  691. ],
  692. advanceRatio: [
  693. { required: true, message: "请输入预付比例", trigger: "blur" },
  694. ],
  695. tradeMethods: [
  696. { required: true, message: "请选择贸易方式", trigger: "change" },
  697. ],
  698. transportMethod: [
  699. { required: true, message: "请选择运输方式", trigger: "change" },
  700. ],
  701. transportRemark: [
  702. { required: true, message: "请输入运输说明", trigger: "blur" },
  703. ],
  704. remark: [{ required: true, message: "请输入付款条件", trigger: "blur" }],
  705. });
  706. const getDict = () => {
  707. proxy
  708. .getDictOne([
  709. "account_currency",
  710. "funds_payment_method",
  711. "trade_mode",
  712. "shipping_method",
  713. "unit",
  714. ])
  715. .then((res) => {
  716. accountCurrency.value = res["account_currency"].map((x) => ({
  717. label: x.dictValue,
  718. value: x.dictKey,
  719. }));
  720. fundsPaymentMethod.value = res["funds_payment_method"].map((x) => ({
  721. label: x.dictValue,
  722. value: x.dictKey,
  723. }));
  724. tradeMethods.value = res["trade_mode"].map((x) => ({
  725. label: x.dictValue,
  726. value: x.dictKey,
  727. }));
  728. shippingMethod.value = res["shipping_method"].map((x) => ({
  729. label: x.dictValue,
  730. value: x.dictKey,
  731. }));
  732. productUnit.value = res["unit"].map((x) => ({
  733. label: x.dictValue,
  734. value: x.dictKey,
  735. }));
  736. });
  737. proxy
  738. .post("/contractTemplate/page", { pageNum: 1, pageSize: 999 })
  739. .then((res) => {
  740. templateList.value = res.rows.map((item) => {
  741. return {
  742. ...item,
  743. label: item.templateName,
  744. value: item.id,
  745. };
  746. });
  747. });
  748. proxy.post("/corporation/page", { pageNum: 1, pageSize: 999 }).then((res) => {
  749. corporationList.value = res.rows.map((item) => {
  750. return {
  751. ...item,
  752. label: item.name,
  753. value: item.id,
  754. };
  755. });
  756. });
  757. };
  758. getDict();
  759. const changeTemplate = (val) => {
  760. formData.data.sellCorporationId = "";
  761. formData.data.sellContactName = "";
  762. formData.data.sellContactNumber = "";
  763. formData.data.sellCountryName = "";
  764. formData.data.sellProvinceName = "";
  765. formData.data.sellCityName = "";
  766. formData.data.sellAddress = "";
  767. if (val) {
  768. proxy.post("/contractTemplate/detail", { id: val }).then((res) => {
  769. formData.data.sellCorporationId = res.corporationId;
  770. if (res.corporationId) {
  771. proxy
  772. .post("/corporation/detail", { id: res.corporationId })
  773. .then((detailCorporation) => {
  774. if (detailCorporation.countryEnStr) {
  775. formData.data.sellCountryName = detailCorporation.countryEnStr;
  776. }
  777. if (detailCorporation.provinceEnStr) {
  778. formData.data.sellProvinceName = detailCorporation.provinceEnStr;
  779. }
  780. if (detailCorporation.cityEnStr) {
  781. formData.data.sellCityName = detailCorporation.cityEnStr;
  782. }
  783. if (detailCorporation.addressEn) {
  784. formData.data.sellAddress = detailCorporation.addressEn;
  785. }
  786. // proxy.post("/customizeArea/list", { parentId: "0" }).then((resCountry) => {
  787. // let sellCountryData = resCountry.filter((item) => item.id === detailCorporation.countryId);
  788. // if (sellCountryData && sellCountryData.length > 0) {
  789. // formData.data.sellCountryName = sellCountryData[0].chineseName;
  790. // } else {
  791. // formData.data.sellCountryName = "";
  792. // }
  793. // });
  794. // if (detailCorporation.countryId) {
  795. // proxy.post("/customizeArea/list", { parentId: detailCorporation.countryId }).then((resProvince) => {
  796. // let sellProvinceData = resProvince.filter((item) => item.id === detailCorporation.provinceId);
  797. // if (sellProvinceData && sellProvinceData.length > 0) {
  798. // formData.data.sellProvinceName = sellProvinceData[0].name;
  799. // } else {
  800. // formData.data.sellProvinceName = "";
  801. // }
  802. // });
  803. // } else {
  804. // formData.data.sellProvinceName = "";
  805. // }
  806. // if (detailCorporation.provinceId) {
  807. // proxy.post("/customizeArea/list", { parentId: detailCorporation.provinceId }).then((resCity) => {
  808. // let sellCityData = resCity.filter((item) => item.id === detailCorporation.cityId);
  809. // if (sellCityData && sellCityData.length > 0) {
  810. // formData.data.sellCityName = sellCityData[0].name;
  811. // } else {
  812. // formData.data.sellCityName = "";
  813. // }
  814. // });
  815. // } else {
  816. // formData.data.sellCityName = "";
  817. // }
  818. // formData.data.sellAddress = detailCorporation.address;
  819. });
  820. }
  821. formData.data.sellContactName = res.contactName;
  822. formData.data.sellContactNumber = res.contactNumber;
  823. });
  824. }
  825. };
  826. const getCityData = (id, type, isChange) => {
  827. proxy.post("/customizeArea/list", { parentId: id }).then((res) => {
  828. if (type === "20") {
  829. provinceData.value = res;
  830. if (isChange) {
  831. formData.data.provinceId = "";
  832. formData.data.provinceName = "";
  833. formData.data.cityId = "";
  834. formData.data.cityName = "";
  835. }
  836. } else if (type === "30") {
  837. cityData.value = res;
  838. if (isChange) {
  839. formData.data.cityId = "";
  840. formData.data.cityName = "";
  841. }
  842. } else {
  843. countryData.value = res;
  844. }
  845. });
  846. };
  847. getCityData("0");
  848. const changeCustomer = (val) => {
  849. formData.data.buyContactName = "";
  850. formData.data.buyContactNumber = "";
  851. if (val) {
  852. proxy.post("/customer/detail", { id: val }).then(
  853. (res) => {
  854. if (res.customerUserList && res.customerUserList.length > 0) {
  855. formData.data.buyContactName = res.customerUserList[0].name;
  856. if (res.customerUserList[0].contactJson) {
  857. let contactJson = JSON.parse(res.customerUserList[0].contactJson);
  858. if (contactJson && contactJson.length > 0) {
  859. formData.data.buyContactNumber = contactJson[0].contactNo;
  860. }
  861. }
  862. customerUserList.value = res.customerUserList.map((item) => {
  863. return {
  864. ...item,
  865. value: item.name,
  866. };
  867. });
  868. }
  869. formData.data.countryId = res.countryId;
  870. formData.data.provinceId = res.provinceId;
  871. formData.data.cityId = res.cityId;
  872. formData.data.buyPostalCode = res.zipCode;
  873. formData.data.buyAddress = res.address;
  874. getCityData(formData.data.countryId, "20");
  875. if (formData.data.provinceId) {
  876. getCityData(formData.data.provinceId, "30");
  877. }
  878. },
  879. (err) => {
  880. console.log(err);
  881. formData.data.countryId = "";
  882. formData.data.provinceId = "";
  883. formData.data.cityId = "";
  884. formData.data.buyPostalCode = "";
  885. formData.data.buyAddress = "";
  886. }
  887. );
  888. } else {
  889. formData.data.countryId = "";
  890. formData.data.provinceId = "";
  891. formData.data.cityId = "";
  892. formData.data.buyPostalCode = "";
  893. formData.data.buyAddress = "";
  894. }
  895. };
  896. const createFilter = (queryString) => {
  897. return (restaurant) => {
  898. return (
  899. restaurant.value.toLowerCase().indexOf(queryString.toLowerCase()) === 0
  900. );
  901. };
  902. };
  903. const querySearchPerson = (queryString, callback) => {
  904. const results = queryString
  905. ? customerUserList.value.filter(createFilter(queryString))
  906. : customerUserList.value;
  907. callback(results);
  908. };
  909. const handlePerson = (item) => {
  910. formData.data.buyContactNumber = item.phone;
  911. };
  912. const pushGoods = (goods) => {
  913. if (goods && goods.length > 0) {
  914. let afterFiltering = [];
  915. if (
  916. formData.data.quotationProductList &&
  917. formData.data.quotationProductList.length > 0
  918. ) {
  919. afterFiltering = goods.filter((item) => {
  920. let data = formData.data.quotationProductList.filter(
  921. (itemProduct) => itemProduct.productId === item.id
  922. );
  923. if (data && data.length > 0) {
  924. return false;
  925. }
  926. return true;
  927. });
  928. } else {
  929. afterFiltering = goods;
  930. }
  931. formData.data.quotationProductList =
  932. formData.data.quotationProductList.concat(
  933. afterFiltering.map((item) => {
  934. let fileUrl = "";
  935. if (item.fileList && item.fileList.length > 0) {
  936. fileUrl = item.fileList[0].fileUrl;
  937. }
  938. let name = item.name;
  939. if (item.standardJson) {
  940. let standardJson = JSON.parse(item.standardJson);
  941. if (standardJson && standardJson.englishName) {
  942. name = standardJson.englishName;
  943. }
  944. }
  945. return {
  946. fileUrl: fileUrl,
  947. code: item.code,
  948. productId: item.id,
  949. name: item.name,
  950. productName: name,
  951. productModel: item.spec,
  952. unit: item.unit,
  953. quantity: undefined,
  954. price: undefined,
  955. amount: "",
  956. remark: item.remark,
  957. };
  958. })
  959. );
  960. ElMessage({
  961. message: "添加成功!",
  962. type: "success",
  963. });
  964. openProduct.value = false;
  965. } else {
  966. ElMessage("请选择至少一件商品");
  967. }
  968. };
  969. const onPicture = (path) => {
  970. window.open(path, "_blank");
  971. };
  972. const handleRemove = async (index) => {
  973. await formData.data.quotationProductList.splice(index, 1);
  974. totalAmount();
  975. };
  976. const calculationAmount = (listLabel, index, label) => {
  977. if (formData.data[listLabel][index][label]) {
  978. formData.data[listLabel][index][label] = Number(
  979. Math.round(Number(formData.data[listLabel][index][label]) * 10000) / 10000
  980. );
  981. }
  982. nextTick(() => {
  983. if (
  984. formData.data.quotationProductList &&
  985. formData.data.quotationProductList.length > 0
  986. ) {
  987. for (let i = 0; i < formData.data.quotationProductList.length; i++) {
  988. let money = 0;
  989. if (
  990. formData.data.quotationProductList[i].quantity &&
  991. formData.data.quotationProductList[i].price
  992. ) {
  993. money = Number(
  994. Math.round(
  995. Number(formData.data.quotationProductList[i].quantity) *
  996. Number(formData.data.quotationProductList[i].price) *
  997. 10000
  998. ) / 10000
  999. );
  1000. }
  1001. formData.data.quotationProductList[i].amount = money;
  1002. }
  1003. }
  1004. nextTick(() => {
  1005. totalAmount();
  1006. });
  1007. });
  1008. };
  1009. const totalAmount = (listLabel, index, label) => {
  1010. if (listLabel && formData.data[listLabel][index][label]) {
  1011. formData.data[listLabel][index][label] = Number(
  1012. Math.round(Number(formData.data[listLabel][index][label]) * 10000) / 10000
  1013. );
  1014. }
  1015. let money = 0;
  1016. if (
  1017. formData.data.quotationProductList &&
  1018. formData.data.quotationProductList.length > 0
  1019. ) {
  1020. for (let i = 0; i < formData.data.quotationProductList.length; i++) {
  1021. if (formData.data.quotationProductList[i].amount) {
  1022. money = Number(
  1023. Math.round(
  1024. (Number(money) +
  1025. Number(formData.data.quotationProductList[i].amount)) *
  1026. 10000
  1027. ) / 10000
  1028. );
  1029. }
  1030. }
  1031. }
  1032. if (
  1033. formData.data.quotationPayList &&
  1034. formData.data.quotationPayList.length > 0
  1035. ) {
  1036. for (let i = 0; i < formData.data.quotationPayList.length; i++) {
  1037. if (formData.data.quotationPayList[i].amount) {
  1038. money = Number(
  1039. Math.round(
  1040. (Number(money) + Number(formData.data.quotationPayList[i].amount)) *
  1041. 10000
  1042. ) / 10000
  1043. );
  1044. }
  1045. }
  1046. }
  1047. formData.data.amount = money;
  1048. };
  1049. const clickAdd = () => {
  1050. if (
  1051. formData.data.quotationPayList &&
  1052. formData.data.quotationPayList.length > 0
  1053. ) {
  1054. formData.data.quotationPayList.push({
  1055. payName: "",
  1056. amount: undefined,
  1057. remark: "",
  1058. });
  1059. } else {
  1060. formData.data.quotationPayList = [
  1061. { payName: "", amount: undefined, remark: "" },
  1062. ];
  1063. }
  1064. };
  1065. const handleDelete = async (index) => {
  1066. await formData.data.quotationPayList.splice(index, 1);
  1067. totalAmount();
  1068. };
  1069. const querySearch = (queryString, callback) => {
  1070. proxy.post("/quotationPay/page", { payName: queryString }).then((res) => {
  1071. if (res.rows && res.rows.length > 0) {
  1072. res.rows = res.rows.map((item) => {
  1073. return {
  1074. ...item,
  1075. value: item.payName,
  1076. };
  1077. });
  1078. callback(res.rows);
  1079. } else {
  1080. callback([]);
  1081. }
  1082. });
  1083. };
  1084. const handleSubmit = async (flag) => {
  1085. if (flag) {
  1086. return true;
  1087. } else {
  1088. let status = await submit.value.handleSubmit(() => {});
  1089. if (status) {
  1090. if (
  1091. !(
  1092. formData.data.quotationProductList &&
  1093. formData.data.quotationProductList.length > 0
  1094. )
  1095. ) {
  1096. ElMessage("请添加至少一件商品");
  1097. return false;
  1098. }
  1099. return true;
  1100. } else {
  1101. setTimeout(() => {
  1102. const errorDiv = document.getElementsByClassName("is-error");
  1103. errorDiv[0].scrollIntoView();
  1104. }, 0);
  1105. }
  1106. return status;
  1107. }
  1108. };
  1109. // 接收父组件的传值
  1110. const props = defineProps({
  1111. queryData: Object,
  1112. });
  1113. watch(
  1114. props.queryData,
  1115. () => {
  1116. formOption.disabled = judgeStatus();
  1117. if (
  1118. props.queryData &&
  1119. ["10", "20", "30"].includes(route.query.processType)
  1120. ) {
  1121. for (var text in props.queryData) {
  1122. formData.data[text] = props.queryData[text];
  1123. }
  1124. if (
  1125. formData.data.quotationProductList &&
  1126. formData.data.quotationProductList.length > 0
  1127. ) {
  1128. for (let i = 0; i < formData.data.quotationProductList.length; i++) {
  1129. delete formData.data.quotationProductList[i].id;
  1130. proxy
  1131. .post("/productInfo/detail", {
  1132. id: formData.data.quotationProductList[i].productId,
  1133. })
  1134. .then((resProduct) => {
  1135. formData.data.quotationProductList[i].name = resProduct.name;
  1136. formData.data.quotationProductList[i].code = resProduct.code;
  1137. formData.data.quotationProductList[i].unit = resProduct.unit;
  1138. });
  1139. }
  1140. let fileIds = formData.data.quotationProductList.map(
  1141. (item) => item.productId
  1142. );
  1143. proxy
  1144. .post("/fileInfo/getList", { businessIdList: fileIds })
  1145. .then((resFile) => {
  1146. for (
  1147. let i = 0;
  1148. i < formData.data.quotationProductList.length;
  1149. i++
  1150. ) {
  1151. if (
  1152. resFile[formData.data.quotationProductList[i].productId] &&
  1153. resFile[formData.data.quotationProductList[i].productId]
  1154. .length > 0
  1155. ) {
  1156. formData.data.quotationProductList[i].fileUrl =
  1157. resFile[
  1158. formData.data.quotationProductList[i].productId
  1159. ][0].fileUrl;
  1160. }
  1161. }
  1162. });
  1163. }
  1164. if (formData.data.countryId) {
  1165. getCityData(formData.data.countryId, "20");
  1166. }
  1167. if (formData.data.provinceId) {
  1168. getCityData(formData.data.provinceId, "30");
  1169. }
  1170. }
  1171. },
  1172. {
  1173. deep: true,
  1174. }
  1175. );
  1176. onMounted(() => {
  1177. if (!route.query.processType || route.query.processType == 30) {
  1178. proxy
  1179. .post("/customer/privateSeaPage", { pageNum: 1, pageSize: 999 })
  1180. .then((res) => {
  1181. customerList.value = res.rows.map((item) => {
  1182. return {
  1183. ...item,
  1184. label: item.name,
  1185. value: item.id,
  1186. };
  1187. });
  1188. });
  1189. } else {
  1190. proxy.post("/customer/page", { pageNum: 1, pageSize: 999 }).then((res) => {
  1191. customerList.value = res.rows.map((item) => {
  1192. return {
  1193. ...item,
  1194. label: item.name,
  1195. value: item.id,
  1196. };
  1197. });
  1198. });
  1199. }
  1200. // 生成合同、复制报价单
  1201. if (props.queryData.priceSheetId) {
  1202. proxy
  1203. .post("/saleQuotation/detail", { id: props.queryData.priceSheetId })
  1204. .then((res) => {
  1205. res.countryId = res.buyCountryId;
  1206. res.provinceId = res.buyProvinceId;
  1207. res.cityId = res.buyCityId;
  1208. for (var text in res) {
  1209. formData.data[text] = res[text];
  1210. }
  1211. if (
  1212. formData.data.quotationProductList &&
  1213. formData.data.quotationProductList.length > 0
  1214. ) {
  1215. for (let i = 0; i < formData.data.quotationProductList.length; i++) {
  1216. delete formData.data.quotationProductList[i].id;
  1217. proxy
  1218. .post("/productInfo/detail", {
  1219. id: formData.data.quotationProductList[i].productId,
  1220. })
  1221. .then((resProduct) => {
  1222. formData.data.quotationProductList[i].name = resProduct.name;
  1223. formData.data.quotationProductList[i].code = resProduct.code;
  1224. formData.data.quotationProductList[i].unit = resProduct.unit;
  1225. });
  1226. }
  1227. let fileIds = formData.data.quotationProductList.map(
  1228. (item) => item.productId
  1229. );
  1230. proxy
  1231. .post("/fileInfo/getList", { businessIdList: fileIds })
  1232. .then((resFile) => {
  1233. for (
  1234. let i = 0;
  1235. i < formData.data.quotationProductList.length;
  1236. i++
  1237. ) {
  1238. if (
  1239. resFile[formData.data.quotationProductList[i].productId] &&
  1240. resFile[formData.data.quotationProductList[i].productId]
  1241. .length > 0
  1242. ) {
  1243. formData.data.quotationProductList[i].fileUrl =
  1244. resFile[
  1245. formData.data.quotationProductList[i].productId
  1246. ][0].fileUrl;
  1247. }
  1248. }
  1249. });
  1250. }
  1251. delete formData.data.id;
  1252. delete formData.data.code;
  1253. getCityData(formData.data.countryId, "20");
  1254. if (formData.data.provinceId) {
  1255. getCityData(formData.data.provinceId, "30");
  1256. }
  1257. if (
  1258. formData.data.quotationPayList &&
  1259. formData.data.quotationPayList.length > 0
  1260. ) {
  1261. formData.data.quotationPayList = formData.data.quotationPayList.map(
  1262. (item) => {
  1263. delete item.id;
  1264. return {
  1265. ...item,
  1266. };
  1267. }
  1268. );
  1269. }
  1270. });
  1271. }
  1272. if (!route.query.processType && route.query.priceSheetIdOne) {
  1273. proxy
  1274. .post("/saleQuotation/detail", { id: props.queryData.priceSheetIdOne })
  1275. .then((res) => {
  1276. if (res && res.dataJson) {
  1277. res = { ...res, ...JSON.parse(res.dataJson) };
  1278. }
  1279. res.countryId = res.buyCountryId;
  1280. res.provinceId = res.buyProvinceId;
  1281. res.cityId = res.buyCityId;
  1282. for (var text in res) {
  1283. formData.data[text] = res[text];
  1284. }
  1285. if (
  1286. formData.data.quotationProductList &&
  1287. formData.data.quotationProductList.length > 0
  1288. ) {
  1289. let fileIds = formData.data.quotationProductList.map(
  1290. (item) => item.productId
  1291. );
  1292. proxy
  1293. .post("/fileInfo/getList", { businessIdList: fileIds })
  1294. .then((resFile) => {
  1295. for (
  1296. let i = 0;
  1297. i < formData.data.quotationProductList.length;
  1298. i++
  1299. ) {
  1300. if (
  1301. resFile[formData.data.quotationProductList[i].productId] &&
  1302. resFile[formData.data.quotationProductList[i].productId]
  1303. .length > 0
  1304. ) {
  1305. formData.data.quotationProductList[i].fileUrl =
  1306. resFile[
  1307. formData.data.quotationProductList[i].productId
  1308. ][0].fileUrl;
  1309. }
  1310. }
  1311. });
  1312. }
  1313. getCityData(formData.data.countryId, "20");
  1314. if (formData.data.provinceId) {
  1315. getCityData(formData.data.provinceId, "30");
  1316. }
  1317. });
  1318. }
  1319. });
  1320. const getFormData = () => {
  1321. return proxy.deepClone(formData.data);
  1322. };
  1323. // 向父组件暴露
  1324. defineExpose({
  1325. getFormData,
  1326. handleSubmit,
  1327. });
  1328. const acquireSelectList = () => {
  1329. let data = [];
  1330. if (
  1331. formData.data.quotationProductList &&
  1332. formData.data.quotationProductList.length > 0
  1333. ) {
  1334. data = formData.data.quotationProductList.map((item) => {
  1335. return {
  1336. id: item.productId,
  1337. name: item.name,
  1338. };
  1339. });
  1340. }
  1341. return data;
  1342. };
  1343. </script>
  1344. <style lang="scss" scoped>
  1345. ::v-deep(.el-input-number .el-input__inner) {
  1346. text-align: left;
  1347. }
  1348. .pic {
  1349. object-fit: contain;
  1350. width: 50px;
  1351. height: 50px;
  1352. cursor: pointer;
  1353. vertical-align: middle;
  1354. }
  1355. </style>