edit.vue 76 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307
  1. <template>
  2. <div>
  3. <div
  4. v-if="loading"
  5. v-loading="true"
  6. class="view-window"
  7. element-loading-text="Loading..."
  8. element-loading-background="rgba(0, 0, 0, 0.3)"
  9. ></div>
  10. <div class="flex fixed-button-area">
  11. <!-- <el-button @click="() => generatePDF()">generatePDF</el-button> -->
  12. <el-button
  13. type="info"
  14. @click="formVisible = !formVisible"
  15. >
  16. <el-icon
  17. size="18px"
  18. color="#fff"
  19. >
  20. <Switch />
  21. </el-icon>
  22. &nbsp;{{ formVisible ? 'Preview PDF' : 'Show Form' }}
  23. </el-button>
  24. <el-button
  25. type="primary"
  26. :disabled="!formVisible"
  27. @click="checkForm(mainForm)"
  28. >
  29. <el-icon
  30. size="20px"
  31. color="#fff"
  32. >
  33. <FolderAdd />
  34. </el-icon>
  35. &nbsp;Save & Attach
  36. </el-button>
  37. </div>
  38. <div
  39. v-show="formVisible"
  40. class="screen"
  41. >
  42. <div class="flex justify-between page-title-wrap">
  43. <div class="flex">
  44. <el-icon
  45. size="36px"
  46. :color="variables.mainColor"
  47. >
  48. <ShoppingCart />
  49. </el-icon>
  50. <div class="page-title">New Purchase Order</div>
  51. </div>
  52. </div>
  53. <el-form
  54. ref="mainForm"
  55. :model="form"
  56. :rules="formRule"
  57. label-width="120px"
  58. >
  59. <div class="flex items-start">
  60. <div class="layout-left">
  61. <el-form-item
  62. prop="Order_Type"
  63. label="Order Type"
  64. label-width="130px"
  65. >
  66. <el-radio-group v-model="form.Order_Type">
  67. <el-radio
  68. v-for="(item, index) in orderTypeList"
  69. :key="index"
  70. :label="item.label"
  71. :value="item.label"
  72. >
  73. {{ item.label }}
  74. </el-radio>
  75. </el-radio-group>
  76. </el-form-item>
  77. <el-form-item
  78. label="Artwork Link"
  79. prop="Artwork_Link"
  80. label-width="130px"
  81. >
  82. <el-input
  83. v-model="form.Artwork_Link"
  84. placeholder="Please input"
  85. type="textarea"
  86. :rows="3"
  87. ></el-input>
  88. </el-form-item>
  89. <el-form-item
  90. label="Currency"
  91. label-width="130px"
  92. >
  93. <el-select
  94. v-model="form.Currency"
  95. style="width: 100%"
  96. placeholder="please select currency"
  97. >
  98. <el-option
  99. v-for="(item, index) in currencyList"
  100. :key="index"
  101. :label="item.label"
  102. :value="item.label"
  103. />
  104. </el-select>
  105. </el-form-item>
  106. <el-form-item
  107. v-if="recommandVendor.length"
  108. label="Frequently Used Supplier"
  109. label-position="right"
  110. label-width="180px"
  111. >
  112. <div class="flex flex-col items-start">
  113. <div class="text-gray-400">最近10个PO的供应商列表</div>
  114. <div
  115. v-for="(item, index) in recommandVendor"
  116. :key="index"
  117. class="btn-quick-vendor"
  118. :class="{ active: item.id === form.currentVendor }"
  119. @click="quickSelectSupplier(item)"
  120. >
  121. {{ item.name || '' }}
  122. </div>
  123. </div>
  124. </el-form-item>
  125. </div>
  126. <div class="layout-right flex-auto">
  127. <div style="position: absolute; right: 24px; top: 0">
  128. <el-form-item label="Template:">
  129. <el-select
  130. v-model="currentCompany"
  131. style="width: 150px"
  132. @change="onCompanyTemplateChange"
  133. >
  134. <el-option
  135. v-for="company in computedCompanyList"
  136. :key="company.id"
  137. :value="company.id"
  138. :label="company.label"
  139. ></el-option>
  140. </el-select>
  141. </el-form-item>
  142. </div>
  143. <div class="company-info">
  144. <div class="company-name">{{ computedCompany.name }}</div>
  145. <div class="flex justify-center">
  146. <div class="company-addr">
  147. 地址:&nbsp;{{ computedCompany.addr }}
  148. </div>
  149. <div class="company-phone">
  150. &nbsp;|&nbsp;电话:&nbsp;{{ computedCompany.phone }}
  151. </div>
  152. <div
  153. v-show="computedCompany.fax"
  154. class="company-fax"
  155. >
  156. &nbsp;|&nbsp;传真:&nbsp;{{ computedCompany.fax }}
  157. </div>
  158. </div>
  159. </div>
  160. <div class="pdf-title">采购合同</div>
  161. <div class="pdf-title-bg">
  162. <div class="left"></div>
  163. <div class="right"></div>
  164. </div>
  165. <div class="flex items-start justify-between form-area">
  166. <div class="form-area-left">
  167. <div class="">
  168. <span style="color: #f56c6c">*</span>
  169. 供应商(乙方) :
  170. </div>
  171. <div>{{ computedVendor.Primary_Contact_name }}</div>
  172. <el-form-item
  173. label-width="0"
  174. prop="currentVendor"
  175. >
  176. <el-select
  177. v-model="form.currentVendor"
  178. :remote-method="utils.debounce(getSupplierLists, 1000)"
  179. remote
  180. style="width: 100%"
  181. :loading="vendorLoading"
  182. filterable
  183. clearable
  184. >
  185. <el-option
  186. v-for="option in vendorList"
  187. :key="option.value"
  188. :value="option.value"
  189. :label="option.label"
  190. ></el-option>
  191. </el-select>
  192. </el-form-item>
  193. <div
  194. v-if="typeof computedCompany.taxReimbursement === 'undefined'"
  195. style="white-space: pre-wrap"
  196. >
  197. {{ computedVendor.PDF_display }}
  198. </div>
  199. <div
  200. v-else
  201. style="white-space: pre-wrap"
  202. >
  203. {{ computedVendor.PDF_display2 }}
  204. </div>
  205. </div>
  206. <div class="form-area-right">
  207. <el-form-item label="采购订单 #:">
  208. Generate once PO submitted
  209. </el-form-item>
  210. <el-form-item label="订单号 # :">
  211. <el-input
  212. v-model="form.Reference"
  213. disabled
  214. ></el-input>
  215. </el-form-item>
  216. <el-form-item
  217. label="日期:"
  218. prop="PO_Date"
  219. >
  220. <el-date-picker
  221. v-model="form.PO_Date"
  222. format="YYYY-MM-DD"
  223. value-format="YYYY-MM-DD"
  224. style="width: 100%"
  225. type="date"
  226. ></el-date-picker>
  227. </el-form-item>
  228. <el-form-item label="付款方式 :">
  229. <el-select
  230. v-model="form.Supplier_Payment_Terms"
  231. style="width: 100%"
  232. >
  233. <el-option
  234. v-for="(item, index) in supplierPaymentTermsLists"
  235. :key="index"
  236. :value="item.label"
  237. :label="item.label"
  238. ></el-option>
  239. </el-select>
  240. </el-form-item>
  241. <el-form-item label="参考 :">
  242. <el-input v-model="form.Title"></el-input>
  243. </el-form-item>
  244. <!-- 退税版没有这几项 -->
  245. <template
  246. v-if="typeof computedCompany.taxReimbursement === 'undefined'"
  247. >
  248. <el-form-item label="收货详情 :">
  249. <el-select
  250. v-model="form.field9"
  251. style="width: 100%"
  252. >
  253. <el-option
  254. v-for="(item, index) in addressList"
  255. :key="index"
  256. :value="item.label"
  257. :label="item.label"
  258. ></el-option>
  259. </el-select>
  260. </el-form-item>
  261. <el-form-item
  262. label="收件人 :"
  263. prop="field7"
  264. >
  265. <el-input v-model="form.field7"></el-input>
  266. </el-form-item>
  267. <el-form-item
  268. label="联系电话 :"
  269. prop="field8"
  270. >
  271. <el-input v-model="form.field8"></el-input>
  272. </el-form-item>
  273. </template>
  274. <el-form-item
  275. label="工厂交货日期 :"
  276. prop="field6"
  277. >
  278. <el-date-picker
  279. v-model="form.field6"
  280. style="width: 100%"
  281. format="YYYY-MM-DD"
  282. value-format="YYYY-MM-DD"
  283. ></el-date-picker>
  284. </el-form-item>
  285. <el-form-item label="送货备注 :">
  286. <el-input v-model="form.Delivery_Details"></el-input>
  287. </el-form-item>
  288. </div>
  289. </div>
  290. <div class="product-table-separator"></div>
  291. <div class="product-table">
  292. <table
  293. border="0"
  294. cellspacing="0"
  295. >
  296. <tr>
  297. <th class="product">品名</th>
  298. <th class="quantity">数量</th>
  299. <th class="rate">价格&nbsp;({{ currentCurrency.label }})</th>
  300. <th class="requirement">中文品目|要求</th>
  301. <th class="amount">金额</th>
  302. <th class="discount">折扣</th>
  303. <th class="warehouse">Warehouse</th>
  304. <th class="action">操作</th>
  305. </tr>
  306. <tr
  307. v-for="(product, index) in form.productList"
  308. :key="index"
  309. >
  310. <td class="product">
  311. <el-form-item
  312. label-width="0"
  313. :prop="'productList.' + index + '.id'"
  314. :rules="{
  315. required: true,
  316. message: '必填项',
  317. trigger: ['blur', 'change'],
  318. }"
  319. >
  320. <el-select-v2
  321. v-model="product.id"
  322. popper-class="product-select"
  323. style="width: 100%; margin-bottom: 4pt"
  324. :options="product.candidate"
  325. :loading="productLoading"
  326. :remote-method="
  327. (e: string) => getProductList(e, product)
  328. "
  329. remote
  330. filterable
  331. clearable
  332. @change="(e) => onProductSelect(e, product)"
  333. ></el-select-v2>
  334. </el-form-item>
  335. <el-input
  336. v-if="userInfo.Organization !== 'PrimePac'"
  337. v-model="product.desc"
  338. type="textarea"
  339. placeholder="Free text"
  340. ></el-input>
  341. </td>
  342. <td class="quantity">
  343. <el-form-item
  344. label-width="0"
  345. :prop="'productList.' + index + '.quantity'"
  346. :rules="{
  347. required: true,
  348. message: '必填项',
  349. trigger: ['blur', 'change'],
  350. }"
  351. >
  352. <el-input
  353. v-model="product.quantity"
  354. type="number"
  355. min="1"
  356. @change="(e) => onInputChange(e, product, 'quantity')"
  357. ></el-input>
  358. </el-form-item>
  359. </td>
  360. <td class="rate">
  361. <el-form-item
  362. label-width="0"
  363. :prop="'productList.' + index + '.rate'"
  364. :rules="{
  365. required: true,
  366. message: '必填项',
  367. trigger: ['blur', 'change'],
  368. }"
  369. >
  370. <el-input
  371. v-model="product.rate"
  372. type="number"
  373. @change="(e) => onInputChange(e, product, 'rate')"
  374. ></el-input>
  375. </el-form-item>
  376. </td>
  377. <td class="requirement">
  378. <el-input
  379. v-model="product.requirement"
  380. :rows="userInfo.Organization !== 'PrimePac' ? 4 : 5"
  381. type="textarea"
  382. placeholder="Free text"
  383. ></el-input>
  384. </td>
  385. <td class="amount">
  386. <el-input
  387. v-model="product.amount"
  388. type="number"
  389. disabled
  390. ></el-input>
  391. </td>
  392. <td class="discount">
  393. <el-input
  394. v-model="product.discount"
  395. type="number"
  396. @change="(e) => onInputChange(e, product, 'discount')"
  397. ></el-input>
  398. </td>
  399. <td class="">
  400. <el-form-item
  401. label-width="0"
  402. :prop="'productList.' + index + '.Warehouse'"
  403. :rules="{
  404. required: product.CF_Product_Type === 'Stock',
  405. message: '必填项',
  406. trigger: ['blur', 'change'],
  407. }"
  408. >
  409. <el-select
  410. v-model="product.Warehouse"
  411. clearable
  412. >
  413. <el-option
  414. v-for="v in warehouseList"
  415. :key="v"
  416. :label="v"
  417. :value="v"
  418. ></el-option>
  419. </el-select>
  420. </el-form-item>
  421. </td>
  422. <td class="action">
  423. <el-button
  424. size="small"
  425. type="danger"
  426. plain
  427. @click="form.productList.splice(index, 1)"
  428. >
  429. Delete
  430. </el-button>
  431. </td>
  432. </tr>
  433. </table>
  434. </div>
  435. <div>
  436. <el-button
  437. type="primary"
  438. size="small"
  439. plain
  440. @click="addRow"
  441. >
  442. Add Row
  443. </el-button>
  444. </div>
  445. <div class="flex justify-end">
  446. <div class="product-total-table">
  447. <div class="total-item">
  448. <div class="label">Sub Total</div>
  449. <div class="value">{{ toFixed(subTotal, 2) }}</div>
  450. </div>
  451. <div class="total-item">
  452. <div class="label">Total Discount</div>
  453. <div class="value">
  454. {{ toFixed(totalDiscount, 2) }}
  455. </div>
  456. </div>
  457. <div class="total-item">
  458. <div class="label">Adjustment</div>
  459. <div class="value">
  460. <el-input
  461. v-model="adjustment"
  462. style="width: 100%"
  463. type="number"
  464. ></el-input>
  465. </div>
  466. </div>
  467. <div class="total-item">
  468. <div class="label">Grand Total</div>
  469. <div class="value">
  470. {{ toFixed(grandTotal, 2) }}
  471. </div>
  472. </div>
  473. </div>
  474. </div>
  475. <div
  476. v-if="userInfo.Organization !== 'PrimePac'"
  477. class="note-form-area"
  478. >
  479. <div class="sub-form-title">注意事项:</div>
  480. <el-form-item label="印刷质量:">
  481. <el-input
  482. v-model="form.field12"
  483. type="textarea"
  484. :rows="3"
  485. ></el-input>
  486. </el-form-item>
  487. <el-form-item label="产品质量:">
  488. <el-input
  489. v-model="form.field13"
  490. type="textarea"
  491. :rows="3"
  492. ></el-input>
  493. </el-form-item>
  494. <el-form-item label="质量承诺:">
  495. <el-input
  496. v-model="form.field10"
  497. type="textarea"
  498. :rows="3"
  499. ></el-input>
  500. </el-form-item>
  501. <el-form-item label="箱子箱唛:">
  502. <el-input
  503. v-model="form.field11"
  504. type="textarea"
  505. :rows="3"
  506. ></el-input>
  507. </el-form-item>
  508. </div>
  509. <div class="sub-form-title">服务条款</div>
  510. <template v-if="currentCompany === 'PangeaTaxReimbursement'">
  511. <div class="rule-item flex">
  512. 一、合同价为含税价,税率为:
  513. <span style="color: #f56c6c">*</span>
  514. <el-form-item
  515. label-width="10"
  516. prop="field4"
  517. :rules="{
  518. required: true,
  519. message: '必填项',
  520. trigger: ['blur', 'change'],
  521. }"
  522. >
  523. <el-input
  524. v-model="form.field4"
  525. size="small"
  526. style="width: 120px"
  527. >
  528. <template #append>%</template>
  529. </el-input>
  530. </el-form-item>
  531. </div>
  532. <div class="rule-item flex">
  533. 二、运费条款:
  534. <span style="color: #f56c6c">*</span>
  535. <el-form-item label-width="10">
  536. <el-select
  537. v-model="form.field5"
  538. size="small"
  539. style="width: 110px"
  540. >
  541. <el-option
  542. v-for="(item, index) in field5_lists"
  543. :key="index"
  544. :label="item.label"
  545. :value="item.label"
  546. ></el-option>
  547. </el-select>
  548. </el-form-item>
  549. </div>
  550. </template>
  551. <template
  552. v-if="['PrimePacCommon', 'PrimePacSoft'].includes(currentCompany)"
  553. >
  554. <div class="rule-item">
  555. 一、本采购订单签署原件一式两份,双方各持一份。经双方代表签字或盖章即可生效,并具有同等法律效力。
  556. </div>
  557. <div class="rule-item flex nowrap">
  558. 二、以上价格已含所有产品的制作费、包装费;由
  559. <div class="attention flex nowrap">
  560. <span style="color: #f56c6c">*</span>
  561. <el-form-item label-width="10">
  562. <el-select
  563. v-model="form.field5"
  564. size="small"
  565. style="width: 110px"
  566. >
  567. <el-option
  568. v-for="(item, index) in field5_lists"
  569. :key="index"
  570. :label="item.label"
  571. :value="item.label"
  572. ></el-option>
  573. </el-select>
  574. </el-form-item>
  575. </div>
  576. 运费送货到广州甲方指定的卸货地点,不含税,运费届时实报实销。
  577. </div>
  578. <div class="rule-item">
  579. 三、印刷及工艺要求:乙方需按照甲方图稿或指定样品进行生产,颜色对照潘通色卡或指定样品。
  580. </div>
  581. <div class="rule-item">
  582. 四、付款形式:
  583. <span class="attention">{{ form.Supplier_Payment_Terms }}</span>
  584. 。甲方在乙方完成大货时,先寄大货样品给乙方确认,确认后付清剩余尾款。甲方通过银行转帐的方式付款,乙方账户信息如上。
  585. </div>
  586. <div class="rule-item">
  587. 五、出货标准:五层出口空白硬纸箱,箱内套防潮袋。如实际出货包装与合约要求不符,甲方有权拒收整批货物。
  588. </div>
  589. <div class="rule-item">
  590. 六、订货时间:自合同成立,甲方支付定金并确认图稿后算起。
  591. </div>
  592. <div class="rule-item">
  593. 七、交货期限:自确认图稿时间算起,乙方应于
  594. <span class="attention">{{ form.field6 }}</span>
  595. 前生产好产品,甲方确认并支付剩余款项后,乙方在约定时间内安排发出剩余产品到甲方收货地址。
  596. </div>
  597. </template>
  598. <div
  599. v-for="(item, index) in currentServiceRule"
  600. :key="index"
  601. class="rule-item"
  602. :class="[{ sub: typeof item === 'object' }]"
  603. v-html="typeof item === 'object' ? item.value : item"
  604. ></div>
  605. <template
  606. v-if="['PrimePacCommon', 'PrimePacSoft'].includes(currentCompany)"
  607. >
  608. <div class="sub-form-title">附录</div>
  609. <div
  610. v-for="(item, index) in appendixData"
  611. :key="index"
  612. class="rule-item"
  613. :class="[{ sub: typeof item === 'object' }]"
  614. v-html="typeof item === 'object' ? item.value : item"
  615. ></div>
  616. </template>
  617. <div
  618. v-if="currentCompany === 'PrimePacCommon'"
  619. class="flex items-stretch PrimePac-table"
  620. >
  621. <div class="flex flex-col items-stretch">
  622. <div class="column-item flex justify-center">制作要求</div>
  623. <div class="flex-auto column-item flex justify-center">
  624. 产品外观要求
  625. </div>
  626. </div>
  627. <div class="flex-auto flex flex-col items-stretch">
  628. <div
  629. v-for="(item, index) in PrimePacCommonRuleTableData"
  630. :key="index"
  631. class="flex items-stretch flex-auto"
  632. >
  633. <div class="column-item flex justify-center">
  634. {{ item.project }}
  635. </div>
  636. <div class="column-item flex-auto flex justify-center">
  637. {{ item.method }}
  638. </div>
  639. </div>
  640. </div>
  641. </div>
  642. <div
  643. v-if="currentCompany === 'PrimePacSoft'"
  644. class="flex flex-col items-stretch PrimePac-table"
  645. >
  646. <div class="flex items-stretch">
  647. <div class="flex flex-col items-stretch">
  648. <div class="column-item flex-auto flex justify-center">
  649. 制作要求
  650. </div>
  651. </div>
  652. <div class="flex-auto flex flex-col items-stretch">
  653. <div
  654. v-for="(item, index) in PrimePacSoftRuleTableData1"
  655. :key="index"
  656. class="flex items-stretch flex-auto"
  657. >
  658. <div class="column-item flex justify-center">
  659. {{ item.project }}
  660. </div>
  661. <div class="column-item flex-auto flex justify-center">
  662. {{ item.method }}
  663. </div>
  664. </div>
  665. </div>
  666. </div>
  667. <div class="flex items-stretch">
  668. <div class="flex flex-col items-stretch">
  669. <div class="column-item flex-auto flex justify-center">
  670. 产品技术要求
  671. </div>
  672. </div>
  673. <div class="flex-auto flex flex-col items-stretch">
  674. <div
  675. v-for="(item, index) in PrimePacSoftRuleTableData2"
  676. :key="index"
  677. class="flex items-stretch flex-auto"
  678. >
  679. <div class="column-item flex justify-center">
  680. {{ item.project }}
  681. </div>
  682. <div class="column-item flex-auto flex justify-center">
  683. {{ item.method }}
  684. </div>
  685. </div>
  686. </div>
  687. </div>
  688. </div>
  689. </div>
  690. </div>
  691. </el-form>
  692. <br />
  693. </div>
  694. <div
  695. class="print"
  696. :class="{ hidden: formVisible && !loading }"
  697. >
  698. <div class="pdf-wrap">
  699. <div
  700. id="pdfElement"
  701. ref="pdfElement"
  702. class="preview-area"
  703. >
  704. <div class="company-info">
  705. <div class="company-name">{{ computedCompany.name }}</div>
  706. <div class="flex justify-center">
  707. <div class="company-addr">
  708. 地址:&nbsp;{{ computedCompany.addr }}
  709. </div>
  710. <div class="company-phone">
  711. &nbsp;|&nbsp;电话:&nbsp;{{ computedCompany.phone }}
  712. </div>
  713. <div
  714. v-show="computedCompany.fax"
  715. class="company-fax"
  716. >
  717. &nbsp;|&nbsp;传真:&nbsp;{{ computedCompany.fax }}
  718. </div>
  719. </div>
  720. </div>
  721. <div>
  722. <table class="pdf-title-bg">
  723. <tr>
  724. <td class="left">
  725. <div>&nbsp;</div>
  726. </td>
  727. <td class="center">
  728. <div class="pdf-title">采购合同</div>
  729. </td>
  730. <td class="right">
  731. <div>&nbsp;</div>
  732. </td>
  733. </tr>
  734. </table>
  735. </div>
  736. <div class="form-area flex items-start">
  737. <div class="flex-auto">
  738. <div>供应商(乙方) :</div>
  739. <div
  740. v-if="computedVendor.Primary_Contact_name"
  741. class="column-vendor"
  742. >
  743. {{ computedVendor.Primary_Contact_name }}
  744. </div>
  745. <div class="column-vendor">
  746. {{ computedVendor.label }}
  747. </div>
  748. <div
  749. v-if="typeof computedCompany.taxReimbursement === 'undefined'"
  750. class="column-vendor"
  751. >
  752. {{ computedVendor.PDF_display }}
  753. </div>
  754. <div
  755. v-else
  756. class="column-vendor"
  757. >
  758. {{ computedVendor.PDF_display2 }}
  759. </div>
  760. </div>
  761. <div class="flex-auto">
  762. <div class="flex">
  763. <div class="column-form-label">采购订单 #:</div>
  764. <div class="column-form-value">
  765. {{ longPONumber || '' }}
  766. </div>
  767. </div>
  768. <div class="flex">
  769. <div class="column-form-label">订单号 # :</div>
  770. <div class="column-form-value">
  771. {{ form.Reference }}
  772. </div>
  773. </div>
  774. <div class="flex">
  775. <div class="column-form-label">日期 :</div>
  776. <div class="column-form-value">
  777. {{ form.PO_Date }}
  778. </div>
  779. </div>
  780. <div class="flex">
  781. <div class="column-form-label">付款方式 :</div>
  782. <div class="column-form-value">
  783. {{
  784. form.Supplier_Payment_Terms !== '-None-'
  785. ? form.Supplier_Payment_Terms
  786. : ''
  787. }}
  788. </div>
  789. </div>
  790. <div class="flex items-start">
  791. <div class="column-form-label">参考 :</div>
  792. <div class="column-form-value">
  793. {{ form.Title }}
  794. </div>
  795. </div>
  796. <template
  797. v-if="typeof computedCompany.taxReimbursement === 'undefined'"
  798. >
  799. <div class="flex items-start">
  800. <div class="column-form-label">收货详情 :</div>
  801. <div class="column-form-value">
  802. {{ form.field9 }}
  803. </div>
  804. </div>
  805. <div class="flex">
  806. <div class="column-form-label">收件人 :</div>
  807. <div class="column-form-value">
  808. {{ form.field7 }}
  809. </div>
  810. </div>
  811. <div class="flex">
  812. <div class="column-form-label">联系电话 :</div>
  813. <div class="column-form-value">
  814. {{ form.field8 }}
  815. </div>
  816. </div>
  817. </template>
  818. <div class="flex">
  819. <div class="column-form-label">工厂交货日期 :</div>
  820. <div class="column-form-value">
  821. {{ form.field6 }}
  822. </div>
  823. </div>
  824. <div class="flex">
  825. <div class="column-form-label">送货备注 :</div>
  826. <div class="column-form-value">
  827. {{ form.Delivery_Details }}
  828. </div>
  829. </div>
  830. </div>
  831. </div>
  832. <div class="product-table-separator"></div>
  833. <div class="product-table">
  834. <table
  835. border="0"
  836. cellspacing="0"
  837. >
  838. <tr>
  839. <th class="row-index">#</th>
  840. <th>品名</th>
  841. <th v-if="userInfo.Organization !== 'PrimePac'">
  842. 中文品目|要求
  843. </th>
  844. <th>数量</th>
  845. <th>价格&nbsp;({{ currentCurrency.label }})</th>
  846. <th>金额</th>
  847. </tr>
  848. <tr
  849. v-for="(product, index) in form.productList"
  850. :key="index"
  851. >
  852. <td class="row-index">{{ index + 1 }}.</td>
  853. <td>
  854. <div class="product-name">{{ product.name }}</div>
  855. <div
  856. v-if="userInfo.Organization !== 'PrimePac'"
  857. class="desc"
  858. >
  859. {{ product.desc }}
  860. </div>
  861. <div
  862. v-else
  863. class="desc"
  864. >
  865. {{ product.requirement }}
  866. </div>
  867. </td>
  868. <td v-if="userInfo.Organization !== 'PrimePac'">
  869. {{ product.requirement }}
  870. </td>
  871. <td>
  872. {{ product.quantity }}
  873. </td>
  874. <td>
  875. {{ currentCurrency.country
  876. }}{{ currentCurrency.symbol }}&nbsp;{{
  877. toFixed(Number(product.rate), computedDeci)
  878. }}
  879. </td>
  880. <td>
  881. {{ currentCurrency.country
  882. }}{{ currentCurrency.symbol }}&nbsp;{{
  883. toFixed(Number(product.amount), computedDeci)
  884. }}
  885. </td>
  886. </tr>
  887. </table>
  888. </div>
  889. <!-- <br /> -->
  890. <div class="flex justify-between items-start">
  891. <div
  892. v-if="userInfo.Organization !== 'PrimePac'"
  893. class="note-form-area"
  894. >
  895. <div class="sub-form-title">注意事项:</div>
  896. <div class="">
  897. <div class="label">印刷质量:</div>
  898. <div class="value">{{ form.field12 }}</div>
  899. </div>
  900. <div class="">
  901. <div class="label">产品质量:</div>
  902. <div class="value">{{ form.field13 }}</div>
  903. </div>
  904. <div class="">
  905. <div class="label">质量承诺:</div>
  906. <div class="value">{{ form.field10 }}</div>
  907. </div>
  908. <div class="">
  909. <div class="label">箱子箱唛:</div>
  910. <div class="value">{{ form.field11 }}</div>
  911. </div>
  912. </div>
  913. <div v-else></div>
  914. <div class="product-total-table">
  915. <div class="total-item flex">
  916. <div class="label">小计&nbsp;</div>
  917. <div class="value">
  918. {{ currentCurrency.country
  919. }}{{ currentCurrency.symbol }}&nbsp;{{
  920. toFixed(subTotal, computedDeci)
  921. }}
  922. </div>
  923. </div>
  924. <div class="total-item flex">
  925. <div class="label">合计&nbsp;</div>
  926. <div class="value">
  927. {{ currentCurrency.country
  928. }}{{ currentCurrency.symbol }}&nbsp;{{
  929. toFixed(grandTotal, computedDeci)
  930. }}
  931. </div>
  932. </div>
  933. </div>
  934. </div>
  935. <br />
  936. <div class="sub-form-title">服务条款</div>
  937. <template v-if="currentCompany === 'PangeaTaxReimbursement'">
  938. <div class="rule-item">
  939. 一、合同价为含税价,税率为: {{ form.field4 }} %
  940. </div>
  941. <div class="rule-item">二、运费条款: {{ form.field5 }}</div>
  942. </template>
  943. <template
  944. v-if="['PrimePacCommon', 'PrimePacSoft'].includes(currentCompany)"
  945. >
  946. <div class="rule-item">
  947. 一、本采购订单签署原件一式两份,双方各持一份。经双方代表签字或盖章即可生效,并具有同等法律效力。
  948. </div>
  949. <div class="rule-item flex nowrap">
  950. 二、以上价格已含所有产品的制作费、包装费;由
  951. <span class="attention">{{ form.field5 }}</span>
  952. 运费送货到广州甲方指定的卸货地点,不含税,运费届时实报实销。
  953. </div>
  954. <div class="rule-item">
  955. 三、印刷及工艺要求:乙方需按照甲方图稿或指定样品进行生产,颜色对照潘通色卡或指定样品。
  956. </div>
  957. <div class="rule-item">
  958. 四、付款形式:
  959. <span class="attention">{{ form.Supplier_Payment_Terms }}</span>
  960. 。甲方在乙方完成大货时,先寄大货样品给乙方确认,确认后付清剩余尾款。甲方通过银行转帐的方式付款,乙方账户信息如上。
  961. </div>
  962. <div class="rule-item">
  963. 五、出货标准:五层出口空白硬纸箱,箱内套防潮袋。如实际出货包装与合约要求不符,甲方有权拒收整批货物。
  964. </div>
  965. <div class="rule-item">
  966. 六、订货时间:自合同成立,甲方支付定金并确认图稿后算起。
  967. </div>
  968. <div class="rule-item">
  969. 七、交货期限:自确认图稿时间算起,乙方应于
  970. <span class="attention">{{ form.field6 }}</span>
  971. 前生产好产品,甲方确认并支付剩余款项后,乙方在约定时间内安排发出剩余产品到甲方收货地址。
  972. </div>
  973. </template>
  974. <div
  975. v-for="(item, index) in currentServiceRule"
  976. :key="index"
  977. class="rule-item"
  978. :class="[{ sub: typeof item === 'object' }]"
  979. v-html="typeof item === 'object' ? item.value : item"
  980. ></div>
  981. <template
  982. v-if="['PrimePacCommon', 'PrimePacSoft'].includes(currentCompany)"
  983. >
  984. <div class="sub-form-title">附录</div>
  985. <div
  986. v-for="(item, index) in appendixData"
  987. :key="index"
  988. class="rule-item"
  989. :class="[{ sub: typeof item === 'object' }]"
  990. v-html="typeof item === 'object' ? item.value : item"
  991. ></div>
  992. </template>
  993. <div
  994. v-if="currentCompany === 'PrimePacCommon'"
  995. class="flex items-stretch PrimePac-table"
  996. >
  997. <div class="flex flex-col items-stretch">
  998. <div class="column-item flex justify-center">制作要求</div>
  999. <div class="flex-auto column-item flex justify-center">
  1000. 产品外观要求
  1001. </div>
  1002. </div>
  1003. <div class="flex-auto flex flex-col items-stretch">
  1004. <div
  1005. v-for="(item, index) in PrimePacCommonRuleTableData"
  1006. :key="index"
  1007. class="flex items-stretch flex-auto"
  1008. >
  1009. <div class="column-item flex justify-center">
  1010. {{ item.project }}
  1011. </div>
  1012. <div class="column-item flex-auto flex justify-center">
  1013. {{ item.method }}
  1014. </div>
  1015. </div>
  1016. </div>
  1017. </div>
  1018. <div
  1019. v-if="currentCompany === 'PrimePacSoft'"
  1020. class="flex flex-col items-stretch PrimePac-table"
  1021. >
  1022. <div class="flex items-stretch">
  1023. <div class="flex flex-col items-stretch">
  1024. <div class="column-item flex-auto flex justify-center">
  1025. 制作要求
  1026. </div>
  1027. </div>
  1028. <div class="flex-auto flex flex-col items-stretch">
  1029. <div
  1030. v-for="(item, index) in PrimePacSoftRuleTableData1"
  1031. :key="index"
  1032. class="flex items-stretch flex-auto"
  1033. >
  1034. <div class="column-item flex justify-center">
  1035. {{ item.project }}
  1036. </div>
  1037. <div class="column-item flex-auto flex justify-center">
  1038. {{ item.method }}
  1039. </div>
  1040. </div>
  1041. </div>
  1042. </div>
  1043. <div class="flex items-stretch">
  1044. <div class="flex flex-col items-stretch">
  1045. <div class="column-item flex-auto flex justify-center">
  1046. 产品技术要求
  1047. </div>
  1048. </div>
  1049. <div class="flex-auto flex flex-col items-stretch">
  1050. <div
  1051. v-for="(item, index) in PrimePacSoftRuleTableData2"
  1052. :key="index"
  1053. class="flex items-stretch flex-auto"
  1054. >
  1055. <div class="column-item flex justify-center">
  1056. {{ item.project }}
  1057. </div>
  1058. <div class="column-item flex-auto flex justify-center">
  1059. {{ item.method }}
  1060. </div>
  1061. </div>
  1062. </div>
  1063. </div>
  1064. </div>
  1065. <br />
  1066. <div class="signature-area">
  1067. <div class="company-seal"></div>
  1068. <div
  1069. style="align-items: flex-end"
  1070. :class="{
  1071. flex: ['PrimePacCommon', 'PrimePacSoft'].includes(
  1072. currentCompany,
  1073. ),
  1074. between: ['PrimePacCommon', 'PrimePacSoft'].includes(
  1075. currentCompany,
  1076. ),
  1077. }"
  1078. >
  1079. <div class="first-party">
  1080. <div
  1081. class="flex"
  1082. style="align-items: flex-end"
  1083. >
  1084. <div v-show="!computedCompany.label.includes('Pangea')">
  1085. 甲方(盖章):
  1086. </div>
  1087. <div
  1088. class="sign-wrap"
  1089. :class="{
  1090. pangea: computedCompany.label.includes('Pangea'),
  1091. }"
  1092. >
  1093. <img
  1094. v-if="computedCompany.signPath"
  1095. :src="computedCompany.signPath"
  1096. />
  1097. </div>
  1098. </div>
  1099. <div class="">代表人: {{ userInfo.full_name }}</div>
  1100. <div class="">日期: {{ form.PO_Date }}</div>
  1101. </div>
  1102. <div class="second-party">
  1103. <div class="">乙方(盖章):</div>
  1104. </div>
  1105. </div>
  1106. </div>
  1107. </div>
  1108. </div>
  1109. <div
  1110. v-if="computedCompany.taxReimbursement && false"
  1111. class="pdf-wrap"
  1112. >
  1113. <div
  1114. ref="pdfElement2"
  1115. class="preview-area2"
  1116. >
  1117. <div class="supplier-name">
  1118. {{ computedVendor.Suppliers_Name || computedVendor.Vendor_Name }}
  1119. </div>
  1120. <div class="billing-addr">
  1121. {{ computedVendor.Billing_Address || '' }}
  1122. </div>
  1123. <div class="flex justify-around contact-info">
  1124. <div class="flex">
  1125. <div>Tel No.:</div>
  1126. <div>&nbsp;{{ computedVendor.Phone }}</div>
  1127. </div>
  1128. <div class="flex justify-center">
  1129. <div>E-mail:</div>
  1130. <div class="">&nbsp;{{ computedVendor.Email }}</div>
  1131. </div>
  1132. </div>
  1133. <div class="base-info-area">
  1134. <div class="flex">
  1135. <div class="flex items-start left">
  1136. <div class="base-info-label">TO:</div>
  1137. <div
  1138. v-if="currentCompany === 'AZYTaxReimbursement'"
  1139. class="base-info-value"
  1140. >
  1141. Azy Trading Pty Ltd
  1142. </div>
  1143. <div
  1144. v-else-if="currentCompany === 'FOTTaxReimbursement'"
  1145. class="base-info-value"
  1146. >
  1147. Fair Ocean Trading Australia Pty Ltd
  1148. </div>
  1149. </div>
  1150. <div class="right flex">
  1151. <div class="base-info-label">Date:</div>
  1152. <div class="base-info-value">{{ form.PO_Date }}</div>
  1153. </div>
  1154. </div>
  1155. <div class="flex items-start">
  1156. <div class="left flex items-start">
  1157. <div class="base-info-label">ADD:</div>
  1158. <div>
  1159. <div
  1160. v-if="currentCompany === 'AZYTaxReimbursement'"
  1161. class="base-info-value"
  1162. >
  1163. UNIT 12,21/F WAYSON COMM BLDG NO 28 CONNAUGHT RD WEST SHEUNG
  1164. WAN, HK
  1165. </div>
  1166. <div
  1167. v-else-if="currentCompany === 'FOTTaxReimbursement'"
  1168. class="base-info-value"
  1169. >
  1170. 15/10 Chilvers Road, Thornleigh, NSW 2120
  1171. </div>
  1172. </div>
  1173. </div>
  1174. <div class="right flex">
  1175. <div class="base-info-label">P/I. NO.</div>
  1176. <div class="base-info-value">{{ longPONumber }}</div>
  1177. </div>
  1178. </div>
  1179. <div class="flex items-start">
  1180. <div class="left flex">
  1181. <div class="base-info-label">ATTN:</div>
  1182. <div class="base-info-value">Accounts</div>
  1183. </div>
  1184. <div class="right flex">
  1185. <div class="base-info-label">Reference:</div>
  1186. <div class="base-info-value">{{ PONumber }}</div>
  1187. </div>
  1188. </div>
  1189. <div class="flex items-start">
  1190. <div class="flex left">
  1191. <template v-if="currentCompany === 'FOTTaxReimbursement'">
  1192. <div class="base-info-label">TEL NO:</div>
  1193. <div class="base-info-value">02 9008 1322</div>
  1194. </template>
  1195. <div v-else></div>
  1196. </div>
  1197. <div class="right flex">
  1198. <div class="base-info-label">Payment Term:</div>
  1199. <div class="base-info-value">
  1200. {{ computedVendor.Supplier_Payment_Terms }}
  1201. </div>
  1202. </div>
  1203. </div>
  1204. </div>
  1205. <div class="table-title">PROFORMA INVOICE</div>
  1206. <div class="product-table">
  1207. <table cellspacing="0">
  1208. <tr>
  1209. <th>ITEM</th>
  1210. <th>DESCRIPTION</th>
  1211. <th>QTY(pcs)</th>
  1212. <th>UNIT PRICE</th>
  1213. <th>TOPTAL VALUE</th>
  1214. </tr>
  1215. <tr
  1216. v-for="(product, index) in form.productList"
  1217. :key="index"
  1218. >
  1219. <td>
  1220. <div>{{ product.name }}</div>
  1221. </td>
  1222. <td>
  1223. <div class="desc">{{ product.desc }}</div>
  1224. </td>
  1225. <td>
  1226. {{ product.quantity }}
  1227. </td>
  1228. <td>
  1229. {{ currentCurrency.country
  1230. }}{{ currentCurrency.symbol }}&nbsp;{{
  1231. toFixed(Number(product.rate), computedDeci)
  1232. }}
  1233. </td>
  1234. <td>
  1235. {{ currentCurrency.country
  1236. }}{{ currentCurrency.symbol }}&nbsp;{{
  1237. toFixed(Number(product.amount), computedDeci)
  1238. }}
  1239. </td>
  1240. </tr>
  1241. </table>
  1242. <div class="flex justify-end">
  1243. <div
  1244. class="flex"
  1245. style="margin-top: 10pt"
  1246. >
  1247. <div style="margin: 0 100pt 0 0">TOTAL</div>
  1248. <div>
  1249. {{ currentCurrency.country
  1250. }}{{ currentCurrency.symbol }}&nbsp;{{ subTotal }}
  1251. </div>
  1252. </div>
  1253. </div>
  1254. </div>
  1255. <br />
  1256. <div class="bank-info-area">
  1257. <div class="flex">
  1258. <div>Bank Information</div>
  1259. <div></div>
  1260. </div>
  1261. <div class="flex">
  1262. <div class="bank-info-label">Beneficiary:</div>
  1263. <div class="bank-info-value">
  1264. {{ computedVendor.Suppliers_Name }}dd
  1265. </div>
  1266. </div>
  1267. <div class="flex">
  1268. <div class="bank-info-label">Bank:</div>
  1269. <div class="bank-info-value">
  1270. {{ computedVendor.Bank_Branch_Name }}
  1271. </div>
  1272. </div>
  1273. <div class="flex">
  1274. <div class="bank-info-label">Bank Add:</div>
  1275. <div class="bank-info-value">{{}}</div>
  1276. </div>
  1277. <div class="flex">
  1278. <div class="bank-info-label">A/C No.:</div>
  1279. <div class="bank-info-value">
  1280. {{ computedVendor.Bank_Account }}
  1281. </div>
  1282. </div>
  1283. <div class="flex">
  1284. <div class="bank-info-label">Bank Code:</div>
  1285. <div class="bank-info-value">{{}}</div>
  1286. </div>
  1287. <div class="flex">
  1288. <div class="bank-info-label">SWIFT CODE:</div>
  1289. <div class="bank-info-value">
  1290. {{ computedVendor.Swift_Code_IBAN }}
  1291. </div>
  1292. </div>
  1293. <div class="flex">
  1294. <div class="bank-info-label">Add:</div>
  1295. <div class="bank-info-value">{{}}</div>
  1296. </div>
  1297. </div>
  1298. <br />
  1299. <div class="flex justify-between items-start">
  1300. <div class="">
  1301. <div class="">BUYERS' SIGNATURE</div>
  1302. <div class="sign-wrap">
  1303. <img
  1304. v-if="computedCompany.signPath"
  1305. :src="computedCompany.signPath"
  1306. />
  1307. </div>
  1308. </div>
  1309. <div class="">
  1310. <div class="">SELLER'S SIGNATURE</div>
  1311. </div>
  1312. </div>
  1313. </div>
  1314. </div>
  1315. </div>
  1316. </div>
  1317. </template>
  1318. <script lang="ts" setup>
  1319. import { computed, defineComponent, ref, unref, watch } from 'vue'
  1320. import { useRoute } from 'vue-router'
  1321. import {
  1322. ElButton,
  1323. ElSelectV2,
  1324. ElSelect,
  1325. ElOption,
  1326. ElIcon,
  1327. ElInput,
  1328. ElForm,
  1329. ElFormItem,
  1330. ElDatePicker,
  1331. ElMessage,
  1332. ElNotification,
  1333. ElRadioGroup,
  1334. ElRadio,
  1335. ElMessageBox,
  1336. } from 'element-plus'
  1337. import type { FormInstance } from 'element-plus'
  1338. import { ShoppingCart, FolderAdd, Switch } from '@element-plus/icons-vue'
  1339. import request from '@/utils/axios'
  1340. import dayjs from 'dayjs'
  1341. import jspdf from 'jspdf'
  1342. import html2canvas from 'html2canvas'
  1343. import utils from '@/utils/index'
  1344. import variables from '@/assets/css/var.module.scss'
  1345. import {
  1346. ServiceTypeKeyEnum,
  1347. ISelectItem,
  1348. IProductItem,
  1349. IUser,
  1350. IVendorItem,
  1351. IRecommandVendor,
  1352. IForm,
  1353. } from '@/interface'
  1354. import {
  1355. currencyList,
  1356. orderTypeList,
  1357. formRule,
  1358. emptyProductItem,
  1359. PrimePacList,
  1360. companyList,
  1361. serviceRule,
  1362. appendixData,
  1363. warehouseList,
  1364. productBlackList,
  1365. PrimePacSoftRuleTableData2,
  1366. PrimePacSoftRuleTableData1,
  1367. PrimePacCommonRuleTableData,
  1368. } from './const'
  1369. defineComponent({
  1370. name: 'PurchaseOrderEdit',
  1371. })
  1372. computed(() => {
  1373. return variables
  1374. })
  1375. const formVisible = ref(true)
  1376. const loading = ref(false)
  1377. // 订单ID. 例如 5757019000000683001, 不是串号.
  1378. const POID = ref('')
  1379. // po 串号. 例如 PO2025
  1380. const PONumber = ref('')
  1381. // po 长串号. 例如 ZCPO2025
  1382. const longPONumber = ref('')
  1383. const mainForm = ref<FormInstance>()
  1384. const checkForm = function (formEl: FormInstance | undefined) {
  1385. if (!formEl) return
  1386. formEl.validate((valid, fields) => {
  1387. if (valid) {
  1388. submit()
  1389. } else {
  1390. console.log('check form has not pass!', fields)
  1391. ElMessage.error('请检查表单必填项')
  1392. }
  1393. })
  1394. }
  1395. const submit = () => {
  1396. loading.value = true
  1397. createPurchaseOrders()
  1398. .then(() => {
  1399. // console.log(res)
  1400. getPurchaseOrdersData()
  1401. .then(() => {
  1402. generatePDF()
  1403. .then(() => {
  1404. ElNotification({
  1405. duration: 0,
  1406. type: 'success',
  1407. title: '任务已成功处理',
  1408. message: '本页面将自动跳转',
  1409. })
  1410. const url =
  1411. import.meta.env.VITE_PO_PATH +
  1412. POID.value +
  1413. import.meta.env.VITE_PO_APPEND
  1414. setTimeout(() => {
  1415. window.location.replace(url)
  1416. }, 1000)
  1417. })
  1418. .finally(() => {
  1419. loading.value = false
  1420. })
  1421. })
  1422. .catch(() => {
  1423. // loading.value = false
  1424. const msg = '获取PO详情失败, 未能正确生成PDF'
  1425. console.log(msg)
  1426. ElNotification({ duration: 0, title: msg, type: 'error' })
  1427. })
  1428. })
  1429. .catch(() => {
  1430. // loading.value = false
  1431. const msg = '创建PO失败'
  1432. console.log(msg)
  1433. ElNotification({ duration: 0, title: msg, type: 'error' })
  1434. })
  1435. }
  1436. const pdfElement = ref()
  1437. const pdfElement2 = ref()
  1438. const generatePDF = (ele = pdfElement, isFirstTime = true) => {
  1439. const A4_WIDTH = 592.28
  1440. const A4_HEIGHT = 841.89
  1441. let imageWrapper = unref(ele) // 获取DOM
  1442. // let pageHeight = (imageWrapper.scrollWidth / A4_WIDTH) * A4_HEIGHT
  1443. let pageHeight = (imageWrapper.clientWidth / A4_WIDTH) * A4_HEIGHT
  1444. let lableListID = imageWrapper.querySelectorAll('#pdfElement > div')
  1445. // 进行分割操作,当dom内容已超出a4的高度,则将该dom前插入一个空dom,把他挤下去,分割
  1446. for (let i = 0; i < lableListID.length; i++) {
  1447. let multiple = Math.ceil(
  1448. (lableListID[i].offsetTop + lableListID[i].offsetHeight) / pageHeight,
  1449. )
  1450. if (isSplit(lableListID, i, multiple * pageHeight)) {
  1451. let divParent = lableListID[i].parentNode // 获取该div的父节点
  1452. let newNode = document.createElement('div')
  1453. newNode.className = 'empty-div'
  1454. newNode.style.background = '#fff'
  1455. let _H =
  1456. multiple * pageHeight -
  1457. (lableListID[i].offsetTop + lableListID[i].offsetHeight)
  1458. //留白
  1459. newNode.style.height = _H + 40 + 'px'
  1460. newNode.style.width = '100%'
  1461. let next = lableListID[i].nextSibling // 获取div的下一个兄弟节点
  1462. // 判断兄弟节点是否存在
  1463. if (next) {
  1464. // 存在则将新节点插入到div的下一个兄弟节点之前,即div之后
  1465. divParent.insertBefore(newNode, next)
  1466. } else {
  1467. // 不存在则直接添加到最后,appendChild默认添加到divParent的最后
  1468. divParent.appendChild(newNode)
  1469. }
  1470. }
  1471. }
  1472. return new Promise((resolve) => {
  1473. html2canvas(imageWrapper, {
  1474. allowTaint: true,
  1475. useCORS: true,
  1476. backgroundColor: '#fff', //一定要设背景颜色,否则有的浏览器就会变花~,比如Edge
  1477. scale: 3, // 缩放倍率调整清晰度
  1478. }).then((canvas) => {
  1479. let pdf = new jspdf('p', 'mm', 'a4') //A4纸,纵向
  1480. let ctx = canvas.getContext('2d'),
  1481. a4ContentWidth = 190,
  1482. a4ContentHeight = 277, //A4大小,210mm x 297mm,四边各保留10mm的边距,显示区域190x277
  1483. imgHeight = Math.floor(
  1484. (a4ContentHeight / a4ContentWidth) * canvas.width,
  1485. ), //按A4显示比例换算一页图像的像素高度
  1486. renderedHeight = 0
  1487. while (renderedHeight < canvas.height) {
  1488. let page = document.createElement('canvas')
  1489. page.width = canvas.width
  1490. page.height = Math.min(imgHeight, canvas.height - renderedHeight) //可能内容不足一页
  1491. //用getImageData剪裁指定区域,并画到前面创建的canvas对象中
  1492. // @ts-ignore: Object is possibly 'null'.
  1493. page
  1494. .getContext('2d')
  1495. .putImageData(
  1496. ctx!.getImageData(
  1497. 0,
  1498. renderedHeight,
  1499. canvas.width,
  1500. Math.min(imgHeight, canvas.height - renderedHeight),
  1501. ),
  1502. 0,
  1503. 0,
  1504. )
  1505. // document.body.appendChild(page)
  1506. pdf.addImage(
  1507. page.toDataURL('image/jpeg', 0.5),
  1508. 'JPEG',
  1509. 10,
  1510. 10,
  1511. a4ContentWidth,
  1512. Math.min(
  1513. a4ContentHeight,
  1514. a4ContentWidth * (page.height / page.width),
  1515. ),
  1516. ) //添加图像到页面,保留10mm边距
  1517. renderedHeight += imgHeight
  1518. if (renderedHeight < canvas.height) pdf.addPage() //如果后面还有内容,添加一个空页
  1519. }
  1520. const prefix =
  1521. `${PONumber.value}-${computedVendor.value.label}` +
  1522. (form.value.Title?.length ? `-${form.value.Title}` : '')
  1523. const fileName = isFirstTime ? prefix : prefix + '_2'
  1524. // sendPDF(pdf.output('datauristring'), fileName)
  1525. // .then(() => {
  1526. resolve(true)
  1527. // })
  1528. // 本地备份一下
  1529. pdf.save(fileName + '.pdf')
  1530. })
  1531. })
  1532. }
  1533. const isSplit = function (nodes: any, index: number, pageHeight: number) {
  1534. // 计算当前这块dom是否跨越了a4大小,以此分割
  1535. if (
  1536. nodes[index].offsetTop + nodes[index].offsetHeight < pageHeight &&
  1537. nodes[index + 1] &&
  1538. nodes[index + 1].offsetTop + nodes[index + 1].offsetHeight > pageHeight
  1539. ) {
  1540. return true
  1541. }
  1542. return false
  1543. }
  1544. // const sendPDF = function (file: string, filename = `attachment_file`) {
  1545. // const temp = file.split(',')
  1546. // // @ts-ignore: Object is possibly 'null'.
  1547. // const mimeType = temp[0].match(/:(.*?);/)[1]
  1548. // let extName = mimeType.split('/')[1]
  1549. // let bstr = window.atob(temp[1])
  1550. // let n = bstr.length
  1551. // let result = new Uint8Array(n)
  1552. // while (n--) {
  1553. // result[n] = bstr.charCodeAt(n)
  1554. // }
  1555. // const data = {
  1556. // id: POID.value,
  1557. // file: new File([result], `${filename}.${extName}`, { type: mimeType }),
  1558. // }
  1559. // return new Promise((resolve, reject) => {
  1560. // request
  1561. // .post('/Purchase_orders/uploadAttachmentFile', data, {
  1562. // headers: {
  1563. // 'Content-Type': 'multipart/form-data',
  1564. // },
  1565. // })
  1566. // .then((response) => {
  1567. // if (response.data.code !== 1) {
  1568. // const msg = '自动创建附件失败'
  1569. // ElNotification({ duration: 0, title: msg, type: 'error' })
  1570. // reject(msg)
  1571. // return
  1572. // }
  1573. // ElNotification({
  1574. // duration: 0,
  1575. // title: '自动创建 PDF 成功',
  1576. // type: 'success',
  1577. // })
  1578. // resolve(true)
  1579. // })
  1580. // .catch((e) => {
  1581. // reject(e)
  1582. // })
  1583. // })
  1584. // }
  1585. const createPurchaseOrders = function () {
  1586. const data = JSON.parse(JSON.stringify(unref(form)))
  1587. data.Status = 'Created'
  1588. data.Sub_Total = subTotal.value
  1589. data.Total_Taxes = 0
  1590. data.Total_Discount = totalDiscount.value
  1591. data.Adjustment = Number(adjustment.value)
  1592. data.Grand_Total = grandTotal.value
  1593. data.Subject = '这里不用填'
  1594. data.Created_By = {
  1595. id: userInfo.value.users_id || route.query.user,
  1596. name: userInfo.value.full_name || '',
  1597. }
  1598. data.Owner = {
  1599. id: userInfo.value.users_id || route.query.user,
  1600. name: userInfo.value.full_name || '',
  1601. email: userInfo.value.email || '',
  1602. }
  1603. data.Vendor_Name = {
  1604. id: computedVendor.value.value,
  1605. name: computedVendor.value.label,
  1606. }
  1607. data.Related_Sales_Order = {
  1608. id: form.value.saleOrderId,
  1609. name: form.value.Title,
  1610. }
  1611. data.Purchase_Items = data.productList.map((item: any) => {
  1612. return {
  1613. Warehouse: item.Warehouse || '',
  1614. Quantity: item.quantity,
  1615. Discount: item.discount || 0,
  1616. List_Price: item.rate,
  1617. Tax: 0,
  1618. total: item.amount,
  1619. total_after_discount: Number(item.amount) - Number(item.discount),
  1620. Net_Total: Number(item.amount) - Number(item.discount),
  1621. Description: item.desc,
  1622. Requirement: item.requirement,
  1623. line_tax: [],
  1624. // book: '',
  1625. // id: item.id,
  1626. product: {
  1627. // name: item.name,
  1628. id: item.id,
  1629. // Product_Code: item.Product_Code,
  1630. },
  1631. Product_Name: {
  1632. id: item.id,
  1633. },
  1634. // 这两个是crm有的, 但是文档没有
  1635. List_Price_Non_Currency: item.rate,
  1636. Price_Book_Name: '',
  1637. }
  1638. })
  1639. if (data.productList) delete data.productList
  1640. return new Promise((resolve, reject) => {
  1641. request
  1642. .post('/Purchase_orders/createPurchaseOrders', data, {})
  1643. .then((response) => {
  1644. if (response.data.code !== 1) return
  1645. const res = response.data.result
  1646. if (res.data && res.data.length && res.data[0].code === 'SUCCESS') {
  1647. POID.value = res.data[0].details?.id || ''
  1648. resolve(res.data[0].details?.id)
  1649. ElNotification({
  1650. duration: 0,
  1651. title: '创建 Purchase Order 成功',
  1652. type: 'success',
  1653. })
  1654. } else {
  1655. ElNotification({
  1656. duration: 0,
  1657. title: '未能成功创建PO, 请稍后重试或者联系管理员',
  1658. type: 'error',
  1659. })
  1660. }
  1661. reject('未能成功创建PO')
  1662. })
  1663. .catch((e) => {
  1664. reject(e)
  1665. })
  1666. })
  1667. }
  1668. const getPurchaseOrdersData = function () {
  1669. return new Promise((resolve, reject) => {
  1670. request
  1671. .post('/purchase_orders/getPurchaseOrdersData', {
  1672. id: POID.value,
  1673. })
  1674. .then((response) => {
  1675. if (response.data.code !== 1) {
  1676. reject(false)
  1677. return
  1678. }
  1679. const res = Array.isArray(response.data.result)
  1680. ? response.data.result[0]
  1681. : response.data.result
  1682. longPONumber.value = res.PO_Number || ''
  1683. PONumber.value = res.Purchase_Order_Number || ''
  1684. resolve(true)
  1685. })
  1686. .catch((e) => {
  1687. reject(e)
  1688. })
  1689. })
  1690. }
  1691. const currentCurrency = computed(() => {
  1692. const temp = currencyList.value.filter((i) => i.label === form.value.Currency)
  1693. // 2是人民币
  1694. return temp.length ? temp[0] : temp[2]
  1695. })
  1696. const form = ref<IForm>({
  1697. Order_Type: '',
  1698. Artwork_Link: '',
  1699. Currency: 'CNY',
  1700. // 订单号
  1701. saleOrderId: '',
  1702. Reference: '',
  1703. // 日期
  1704. PO_Date: '',
  1705. // 付款方式
  1706. Supplier_Payment_Terms: '-None-',
  1707. // 参考, so的job name
  1708. Title: '',
  1709. // 收货地址
  1710. field9: '广州市越秀区八旗二马路广东航运大厦1904室 邮编510110',
  1711. // 收件人
  1712. field7: '',
  1713. // 联系电话
  1714. field8: '18925020659',
  1715. // 工厂交货日期
  1716. field6: '',
  1717. productList: [
  1718. {
  1719. name: '',
  1720. id: '',
  1721. quantity: '',
  1722. rate: '',
  1723. requirement: '',
  1724. desc: '',
  1725. amount: 0,
  1726. discount: '',
  1727. candidate: [],
  1728. },
  1729. ] as IProductItem[],
  1730. // 印刷质量
  1731. field12: '',
  1732. // 产品质量
  1733. field13: '',
  1734. // 质量承诺
  1735. field10: '',
  1736. // 箱子箱唛
  1737. field11: '',
  1738. // 税率
  1739. field4: '0',
  1740. // 运费条款
  1741. field5: '供应商承担',
  1742. currentVendor: '',
  1743. Delivery_Details: '',
  1744. })
  1745. const addRow = function () {
  1746. form.value.productList.push(JSON.parse(JSON.stringify(emptyProductItem)))
  1747. }
  1748. const keyNeedCompute = ['quantity', 'rate']
  1749. const onInputChange = function (e: any, obj: IProductItem, key: string) {
  1750. if (typeof e === 'string') {
  1751. if (e.length) {
  1752. // 强制转换为数字类型
  1753. obj[key] = Math.round(utils.multiply(Number(e), 1000)) / 1000
  1754. // 计算每行的总额
  1755. if (keyNeedCompute.includes(key)) {
  1756. obj.amount = utils.multiply(Number(obj.quantity), Number(obj.rate))
  1757. }
  1758. } else {
  1759. // obj[key] = minValue
  1760. }
  1761. }
  1762. }
  1763. const onProductSelect = function (e: any, product: IProductItem) {
  1764. if (e) {
  1765. const temp = product.candidate.filter((i) => i.value === e)
  1766. if (temp.length) {
  1767. product.name = temp[0].label
  1768. product.Product_Code = temp[0].Product_Code // 没有传出去, 实际上没用, 在本页面处于废弃状态
  1769. }
  1770. getProductData(product.id).then((ctx) => {
  1771. product.requirement =
  1772. userInfo.value.Organization === 'PrimePac'
  1773. ? '产品名称:\n尺寸:\n材质:\n工艺:\n颜色:\n其他备注:'
  1774. : ctx.CF3 || ''
  1775. product.CF_Product_Type = ctx.CF_Product_Type || ''
  1776. })
  1777. } else {
  1778. product.name = ''
  1779. }
  1780. }
  1781. // 小计
  1782. const subTotal = computed(() => {
  1783. return form.value.productList.reduce((total, current) => {
  1784. total = total + Number(current.amount)
  1785. return total
  1786. }, 0)
  1787. })
  1788. // 总优惠额度
  1789. const totalDiscount = computed(() => {
  1790. return form.value.productList.reduce((total, current) => {
  1791. total = total + Number(current.discount)
  1792. return total
  1793. }, 0)
  1794. })
  1795. // 价格统计修正值
  1796. const adjustment = ref<number | string>('')
  1797. // 总计
  1798. const grandTotal = computed(() => {
  1799. return subTotal.value - totalDiscount.value + Number(adjustment.value)
  1800. })
  1801. const productLoading = ref(false)
  1802. const getProductList = utils.debounce(
  1803. (keyword: string, target: IProductItem) => {
  1804. const key = keyword.trim()
  1805. if (!key.length) return
  1806. productLoading.value = true
  1807. const data = {
  1808. value: key,
  1809. name: 'Products',
  1810. api_name: 'Product_Name',
  1811. contains: 'contains',
  1812. page: 1,
  1813. limit: 20,
  1814. }
  1815. getSearchData(data)
  1816. .then((response) => {
  1817. if (response.data.code !== 1) return
  1818. const res = response.data.result
  1819. target.candidate = res.data.map((item: any) => {
  1820. return {
  1821. ...item,
  1822. label: item.Product_Name,
  1823. value: item.products_id || item.id,
  1824. }
  1825. })
  1826. })
  1827. .finally(() => {
  1828. productLoading.value = false
  1829. })
  1830. },
  1831. 1000,
  1832. )
  1833. const toFixed = function (value: number, ratio = 2) {
  1834. let r = 100
  1835. if (ratio === 3) {
  1836. r = 1000
  1837. }
  1838. return utils.toFixed(value, r)
  1839. }
  1840. const vendorList = ref<IVendorItem[]>([])
  1841. const computedVendor = computed(() => {
  1842. const temp = vendorList.value.filter(
  1843. (i) => i.value === form.value.currentVendor,
  1844. )
  1845. return temp.length
  1846. ? temp[0]
  1847. : {
  1848. Primary_Contact_name: '',
  1849. PDF_display: '',
  1850. PDF_display2: '',
  1851. label: '',
  1852. value: '',
  1853. Payment_Terms: '',
  1854. High_Risk_Supplier: false,
  1855. }
  1856. })
  1857. watch(computedVendor, () => {
  1858. if (
  1859. computedVendor.value.Payment_Terms &&
  1860. computedVendor.value.Payment_Terms.length
  1861. ) {
  1862. form.value.Supplier_Payment_Terms = computedVendor.value.Payment_Terms
  1863. // 选择供应商后, 对应的currency赋值到界面的Currency选项.
  1864. const temp: any[] = vendorList.value.filter(
  1865. (i) => i.value === form.value.currentVendor,
  1866. )
  1867. if (temp.length) {
  1868. form.value.Currency = temp[0].Currency || 'CNY'
  1869. }
  1870. }
  1871. })
  1872. const vendorLoading = ref(false)
  1873. const getSupplierLists = function (string: string) {
  1874. return new Promise((resolve, reject) => {
  1875. const keyword = string.trim() || ''
  1876. if (!keyword.length) {
  1877. reject('false')
  1878. return
  1879. }
  1880. const query = {
  1881. title: 'Vendors',
  1882. comm: {
  1883. group_operator: 'OR',
  1884. group: [
  1885. {
  1886. comparator: 'contains',
  1887. field: {
  1888. api_name: 'Vendor_Name',
  1889. },
  1890. value: keyword,
  1891. },
  1892. {
  1893. comparator: 'contains',
  1894. field: {
  1895. api_name: 'Previous_Supplier_Name',
  1896. },
  1897. value: keyword,
  1898. },
  1899. ],
  1900. },
  1901. }
  1902. vendorLoading.value = true
  1903. getSearchData2(query)
  1904. .then((response) => {
  1905. if (response.data.code !== 1) return false
  1906. const res = response.data.result || { data: [] }
  1907. vendorList.value = res.data
  1908. .filter((i: any) => !i.Hide_Record)
  1909. .map((i: any) => {
  1910. return {
  1911. ...i,
  1912. label:
  1913. (i.Suppliers_Name || i.Vendor_Name) +
  1914. (i.Previous_Supplier_Name && i.Previous_Supplier_Name != null
  1915. ? ` (曾用名: ${i.Previous_Supplier_Name})`
  1916. : ''),
  1917. value: i.supplier_id || i.id,
  1918. Primary_Contact_name: i.Primary_Contact_name || '',
  1919. PDF_display: i.PDF_display || '',
  1920. PDF_display2: i.PDF_display2 || '',
  1921. }
  1922. })
  1923. if (
  1924. vendorList.value.length === 1 &&
  1925. vendorList.value[0].High_Risk_Supplier === true
  1926. ) {
  1927. ElMessageBox.alert(
  1928. '请注意该供应商在我们黑名单中。<br>Please note that this supplier is in our black list.',
  1929. 'Alert',
  1930. {
  1931. dangerouslyUseHTMLString: true,
  1932. },
  1933. )
  1934. }
  1935. vendorLoading.value = false
  1936. loading.value = false
  1937. resolve(true)
  1938. })
  1939. .catch((e) => reject(e))
  1940. })
  1941. }
  1942. const quickSelectSupplier = function (item: IRecommandVendor) {
  1943. form.value.currentVendor = item.id
  1944. loading.value = true
  1945. getSupplierLists(item.name)
  1946. }
  1947. const getSearchData = async function (p: any) {
  1948. return await request
  1949. .post('/common/getPublicLists', p, {
  1950. headers: { 'Content-Type': 'multipart/form-data' },
  1951. })
  1952. .then((response) => {
  1953. return response
  1954. })
  1955. }
  1956. const getSearchData2 = async function (p: any) {
  1957. return await request.post('/common/getPublicListsAll', p).then((response) => {
  1958. return response
  1959. })
  1960. }
  1961. const computedCompanyList = computed(() => {
  1962. return userInfo.value.Organization === 'PrimePac'
  1963. ? PrimePacList.value
  1964. : companyList.value
  1965. })
  1966. // 切换模版后的处理
  1967. const onCompanyTemplateChange = function () {
  1968. // 重置这两个字段
  1969. form.value.field5 = '供应商承担'
  1970. form.value.field4 = ''
  1971. if (typeof computedCompany.value.taxReimbursement === 'undefined') {
  1972. form.value.field7 = soOwner.value
  1973. form.value.field8 = '18925020659'
  1974. form.value.field9 = '广州市越秀区八旗二马路广东航运大厦1904室 邮编510110'
  1975. } else {
  1976. // 退税版没有这三个表单项, 直接重置值. 相应的, 非退税版要重新赋值.
  1977. form.value.field7 = ''
  1978. form.value.field8 = ''
  1979. form.value.field9 = ''
  1980. }
  1981. }
  1982. const currentServiceRule = computed(() => {
  1983. if (currentCompany.value === 'PrimePacSoft') {
  1984. return serviceRule.value['PrimePacCommon']
  1985. }
  1986. return serviceRule.value[currentCompany.value as ServiceTypeKeyEnum]
  1987. })
  1988. const currentCompany = ref('PC')
  1989. const computedCompany = computed(() => {
  1990. const result = computedCompanyList.value.filter(
  1991. (i) => i.id === currentCompany.value,
  1992. )
  1993. return result.length ? result[0] : computedCompanyList.value[0]
  1994. })
  1995. // 格式化输出价格的小数位数. 退税版需要显示三位小数, 其他只需要两位小数
  1996. const computedDeci = computed(() => {
  1997. return typeof computedCompany.value.taxReimbursement !== 'undefined' ? 3 : 2
  1998. })
  1999. // 候选 收货地址
  2000. let addressList = ref<ISelectItem[]>([])
  2001. // 候选 运费条款. 目前只有庞吉亚退税版用到, 其他模版默认供应商承担
  2002. let field5_lists = ref<ISelectItem[]>([])
  2003. let supplierPaymentTermsLists = ref<ISelectItem[]>([])
  2004. loading.value = true
  2005. // 获取下拉框非动态候选数据
  2006. const p1 = request
  2007. .post('/common/getfieldsData')
  2008. .then((response: any) => {
  2009. const res = response.data.result
  2010. orderTypeList.value = res.Order_Type_lists.map((i: string) => {
  2011. return {
  2012. label: i,
  2013. }
  2014. }).filter((i: any) => i.label !== '-None-')
  2015. addressList.value = res.field9_lists.map((i: any) => {
  2016. return {
  2017. label: i,
  2018. }
  2019. })
  2020. field5_lists.value = res.field5_lists
  2021. .filter((i: string) => !/^-?[Nn]one-?$/.test(i))
  2022. .map((i: any) => {
  2023. return {
  2024. label: i,
  2025. }
  2026. })
  2027. supplierPaymentTermsLists.value = res.Supplier_Payment_Terms_lists.map(
  2028. (i: any) => {
  2029. return {
  2030. label: i,
  2031. }
  2032. },
  2033. )
  2034. })
  2035. .catch((e) => {
  2036. console.log(e, '下拉框')
  2037. ElMessage.error('获取下拉框数据出错, 请联系管理员.')
  2038. })
  2039. const route = useRoute()
  2040. const soOwner = ref('')
  2041. // 获取销售订单详情
  2042. const p2 = request
  2043. .post('/common/getSalesOrdersDatV7', { id: route.params.id })
  2044. // 获取对 该so对应客户的标注 并弹窗提醒
  2045. const getAccountsData = async (id: string) =>
  2046. request.post('/common/getAccountsData', { id }).then((response) => {
  2047. const res = response.data
  2048. if (res.code !== 1) return
  2049. if (res.result.User_Notes && res.result.User_Notes.length) {
  2050. ElMessageBox.confirm(res.result.User_Notes, '', {
  2051. confirmButtonText: '将此备注添加到合同',
  2052. cancelButtonText: '已知悉',
  2053. type: 'warning',
  2054. showClose: false,
  2055. closeOnPressEscape: false,
  2056. closeOnClickModal: false,
  2057. autofocus: false,
  2058. })
  2059. .then(() => {
  2060. // 迭代3 需求. 固定填充一行.
  2061. form.value.productList.push(
  2062. Object.assign({}, emptyProductItem, {
  2063. requirement: res.result.User_Notes || '',
  2064. quantity: 1,
  2065. rate: 0,
  2066. id: '4791186000172849436',
  2067. name: 'User Notes',
  2068. CF_Product_Type: '',
  2069. candidate: [
  2070. {
  2071. label: 'User Notes',
  2072. value: '4791186000172849436',
  2073. },
  2074. ],
  2075. }),
  2076. )
  2077. })
  2078. .catch(() => {})
  2079. }
  2080. })
  2081. const getProductData = async (id: string) =>
  2082. request.post('/common/getProductsData', { id }).then((response) => {
  2083. const res = response.data
  2084. if (res.code !== 1) return
  2085. // 推荐供应商. 用来快速选择供应商的.
  2086. if (
  2087. Array.isArray(res.result.SUPPLIER_PRICING) &&
  2088. res.result.SUPPLIER_PRICING.length
  2089. ) {
  2090. for (const item of res.result.SUPPLIER_PRICING) {
  2091. if (
  2092. item.Supplier?.id &&
  2093. !computedRecommandVendorID.value.includes(item.Supplier.id)
  2094. ) {
  2095. console.log(item, 'item')
  2096. recommandVendor.value.push({
  2097. id: item.Supplier.id,
  2098. name: item.Supplier.name,
  2099. })
  2100. }
  2101. }
  2102. }
  2103. return res.result
  2104. })
  2105. const recommandVendor = ref<IRecommandVendor[]>([])
  2106. // 用来去重
  2107. const computedRecommandVendorID = computed(() =>
  2108. recommandVendor.value.map((i: any) => i.id),
  2109. )
  2110. // 根据url传递过来的用户ID获取的用户身份信息
  2111. const userInfo = ref({} as IUser)
  2112. const p3 = request
  2113. .post('/common/getUsersData', { id: route.query.user })
  2114. .then((response) => {
  2115. const res = response.data
  2116. if (res.code !== 1) return
  2117. if (res.result.users && res.result.users.length) {
  2118. userInfo.value = res.result.users[0]
  2119. } else if (res.result.id) {
  2120. userInfo.value = res.result || {}
  2121. } else if (Array.isArray(res.result) && res.result.length) {
  2122. userInfo.value = res.result[0] || {}
  2123. } else {
  2124. ElMessage.error('获取当前用户身份异常, 请联系管理员')
  2125. }
  2126. // 根据用户 ‘组织’ 切换模版默认选中项
  2127. if (userInfo.value.Organization === 'PrimePac') {
  2128. currentCompany.value = 'PrimePacCommon'
  2129. } else {
  2130. currentCompany.value = 'PC'
  2131. }
  2132. })
  2133. Promise.all([p1, p2, p3, getAccountsData])
  2134. .then((array: any[]) => {
  2135. // p2的数据处理逻辑从原本的p2then移动到这里处理.
  2136. // 因为要根据p3用户数据的Organization 来填充产品列表里面的 requirement, 这步处理必须放在p3后面, 而p2 p3是并发操作.
  2137. if (array[1].data.code !== 1) return
  2138. const res = array[1].data.result
  2139. if (res.Account_Name && res.Account_Name.id) {
  2140. getAccountsData(res.Account_Name.id)
  2141. }
  2142. form.value.field7 = res.Owner_name || res.Owner.name || ''
  2143. soOwner.value = res.Owner_name || res.Owner.name || ''
  2144. form.value.Title =
  2145. res.Contract_Title || res.Sales_Order_Title_Job_Name || ''
  2146. form.value.saleOrderId = res.sales_orders_id || res.id || ''
  2147. form.value.PO_Date = dayjs(new Date()).format('YYYY-MM-DD')
  2148. form.value.Reference = res.Reference || ''
  2149. form.value.Artwork_Link = res.Artwork_Link || ''
  2150. let temp = []
  2151. if (res.Ordered_Items) {
  2152. temp = res.Ordered_Items.filter(
  2153. (item: any) => !productBlackList.includes(item.Product_Name.id),
  2154. )
  2155. }
  2156. if (!temp.length) return
  2157. form.value.productList = []
  2158. recommandVendor.value = []
  2159. temp.forEach((item: any) => {
  2160. getProductData(item.Product_Name.id).then((ctx) => {
  2161. console.log(ctx, 'product ctx')
  2162. form.value.productList.push(
  2163. Object.assign({}, emptyProductItem, {
  2164. candidate: [
  2165. {
  2166. Product_Code: item.Product_Name.Product_Code,
  2167. label: item.Product_Name.name,
  2168. value: item.Product_Name.id,
  2169. },
  2170. ],
  2171. Product_Code: item.Product_Name.Product_Code,
  2172. id: item.Product_Name.id,
  2173. name: item.Product_Name.name,
  2174. label: item.Product_Name.name,
  2175. value: item.Product_Name.id,
  2176. desc: item.Description || '',
  2177. quantity: Number(item.Quantity),
  2178. requirement:
  2179. userInfo.value.Organization === 'PrimePac'
  2180. ? '产品名称:\n尺寸:\n材质:\n工艺:\n颜色:\n其他备注:'
  2181. : ctx.CF3 || '',
  2182. CF_Product_Type: ctx.CF_Product_Type,
  2183. SO_Line_Item_Id: item.id,
  2184. }),
  2185. )
  2186. })
  2187. })
  2188. })
  2189. .finally(() => {
  2190. loading.value = false
  2191. })
  2192. </script>
  2193. <style lang="scss">
  2194. input[type='number'] {
  2195. -moz-appearance: textfield;
  2196. appearance: textfield;
  2197. &:hover {
  2198. -moz-appearance: textfield;
  2199. appearance: textfield;
  2200. &::-webkit-inner-spin-button,
  2201. &::-webkit-outer-spin-button {
  2202. -webkit-appearance: none;
  2203. margin: 0;
  2204. }
  2205. }
  2206. &::-webkit-inner-spin-button,
  2207. &::-webkit-outer-spin-button {
  2208. -webkit-appearance: none;
  2209. margin: 0;
  2210. }
  2211. }
  2212. .product-select {
  2213. .el-select-dropdown,
  2214. .el-select-dropdown__list {
  2215. min-width: 400px;
  2216. max-width: 500px;
  2217. }
  2218. }
  2219. </style>
  2220. <style lang="scss" scoped>
  2221. @import './style.scss';
  2222. </style>