exportQuota2.vue 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499
  1. <template>
  2. <div class="pdf-wrap">
  3. <table
  4. id="pdfTarget"
  5. style="
  6. width: 850px;
  7. line-height: 20px;
  8. font-size: 12px;
  9. font-family:
  10. 'Source Han Sans', 'Open Sans', 'WebFont-Open Sans', Arial, sans-serif;
  11. "
  12. >
  13. <tbody>
  14. <tr>
  15. <td style="vertical-align: bottom">
  16. <img
  17. style="position: relative; left: -10pt"
  18. src="http://zohocrmapi.promocollection.com.au/static/uploads/logo/pdf_logo.png"
  19. height="50px"
  20. />
  21. </td>
  22. <td style="vertical-align: top; text-align: right">
  23. <h1>Quotation</h1>
  24. </td>
  25. </tr>
  26. <tr>
  27. <td style="vertical-align: top">
  28. <template v-if="city2 === 'US'">
  29. <p>Promocollection, LLC</p>
  30. <p>1309 COFFEEN AVE STE 1200</p>
  31. <p>SHERIDAN</p>
  32. <p>WY 82801</p>
  33. </template>
  34. <template v-else>
  35. <p>FAIR OCEAN TRADING AUSTRALIA</p>
  36. <p>PTY LTD</p>
  37. <p>15/10 Chilvers Road,</p>
  38. <p>THORNLEIGH NSW 2120,</p>
  39. <p>AUSTRALIA</p>
  40. </template>
  41. </td>
  42. <td style="vertical-align: top; text-align: right">
  43. <table style="width: 250px; float: right">
  44. <colgroup>
  45. <col width="100px" />
  46. <col width="150px" />
  47. </colgroup>
  48. <tr>
  49. <td><strong>Sales Person:</strong></td>
  50. <td>{{ computedCreator }}</td>
  51. </tr>
  52. <tr>
  53. <td><strong>Order Date:</strong></td>
  54. <td>{{ dayjs().format('DD MMM YYYY') }}</td>
  55. </tr>
  56. </table>
  57. </td>
  58. </tr>
  59. <tr>
  60. <td style="vertical-align: top">
  61. <template v-if="city2 !== 'US'">
  62. <p>
  63. Email:&nbsp;&nbsp;&nbsp;&nbsp;accounts@promocollection.com.au
  64. </p>
  65. <p>Phone Number:&nbsp;&nbsp;&nbsp;&nbsp;02 9008 1152</p>
  66. <p>Fax Number:&nbsp;&nbsp;&nbsp;&nbsp;02 9008 1157</p>
  67. </template>
  68. </td>
  69. <td
  70. rowspan="3"
  71. style="vertical-align: top; text-align: right"
  72. >
  73. <img
  74. v-if="mainPicture"
  75. :src="mainPicture"
  76. width="300px"
  77. />
  78. </td>
  79. </tr>
  80. <tr>
  81. <td style="vertical-align: top">
  82. <p><strong>Information</strong></p>
  83. <p>
  84. <strong>{{ productInfo.product_name }}</strong>
  85. </p>
  86. <p v-if="productInfo.product_size">
  87. <strong>Size:</strong>
  88. {{ productInfo.product_size }}
  89. </p>
  90. <p v-if="productInfo.product_hd">
  91. <strong>Thickness:</strong>
  92. {{ productInfo.product_hd }}
  93. </p>
  94. <p v-if="productInfo.product_capacity">
  95. <strong>Capacity:</strong>
  96. {{ productInfo.product_capacity }}
  97. </p>
  98. <p v-if="productInfo.product_material">
  99. <strong>Material:</strong>
  100. {{ productInfo.product_material }}
  101. </p>
  102. <p v-if="productInfo.product_require_print">
  103. <strong>Print:</strong>
  104. {{ productInfo.product_require_print }}
  105. </p>
  106. <p v-if="productInfo.product_require_color">
  107. <strong>Color requirements:</strong>
  108. {{ productInfo.product_require_color }}
  109. </p>
  110. <p v-if="productInfo.product_color">
  111. <strong>Product Colours Available:</strong>
  112. {{ productInfo.product_color }}
  113. </p>
  114. <p v-if="productInfo.product_battery">
  115. <strong>Whether with battery:</strong>
  116. {{ productInfo.product_battery }}
  117. </p>
  118. <p v-if="productInfo.package_info">
  119. <strong>Packaging:</strong>
  120. {{ productInfo.package_info }}
  121. </p>
  122. <p v-if="productInfo.product_other">
  123. <strong>More Details:</strong>
  124. <span
  125. v-html="productInfo.product_other.replace(/\n/g, '<br>')"
  126. ></span>
  127. </p>
  128. </td>
  129. </tr>
  130. <tr style="vertical-align: top">
  131. <td><p></p></td>
  132. </tr>
  133. <tr style="vertical-align: top">
  134. <td colspan="2">
  135. <table style="width: 800px; border-spacing: 0">
  136. <tbody>
  137. <tr
  138. style="
  139. background-color: #eee;
  140. line-height: 45px;
  141. border-top: solid 1px #ccc;
  142. font-weight: bold;
  143. text-align: center;
  144. "
  145. >
  146. <td
  147. style="
  148. border-top: solid 1px #ccc;
  149. border-bottom: solid 1px #ccc;
  150. width: 20px;
  151. height: 45px;
  152. "
  153. >
  154. #
  155. </td>
  156. <td
  157. style="
  158. border-top: solid 1px #ccc;
  159. border-bottom: solid 1px #ccc;
  160. text-align: left;
  161. width: 230px;
  162. height: 45px;
  163. "
  164. >
  165. Items
  166. </td>
  167. <td
  168. style="
  169. border-top: solid 1px #ccc;
  170. border-bottom: solid 1px #ccc;
  171. width: 120px;
  172. height: 45px;
  173. "
  174. >
  175. Qty
  176. </td>
  177. <td
  178. style="
  179. border-top: solid 1px #ccc;
  180. border-bottom: solid 1px #ccc;
  181. width: 120px;
  182. height: 45px;
  183. "
  184. >
  185. Setup cost
  186. </td>
  187. <td
  188. style="
  189. border-top: solid 1px #ccc;
  190. border-bottom: solid 1px #ccc;
  191. width: 120px;
  192. height: 45px;
  193. "
  194. >
  195. Unit cost
  196. </td>
  197. <td
  198. style="
  199. border-top: solid 1px #ccc;
  200. border-bottom: solid 1px #ccc;
  201. width: 120px;
  202. height: 45px;
  203. "
  204. >
  205. Local Freight
  206. </td>
  207. <td
  208. style="
  209. border-top: solid 1px #ccc;
  210. border-bottom: solid 1px #ccc;
  211. width: 120px;
  212. height: 45px;
  213. "
  214. >
  215. {{ exportForm.gst_name ? 'Total(ex-GST)($)' : 'Total($)' }}
  216. </td>
  217. </tr>
  218. <tr
  219. v-for="(row, index) in step3FormList"
  220. :key="index"
  221. style="text-align: center; line-height: 45px"
  222. >
  223. <td style="border-bottom: solid 1px #ccc; height: 45px">
  224. {{ index + 1 }}
  225. </td>
  226. <td
  227. style="
  228. border-bottom: solid 1px #ccc;
  229. text-align: left;
  230. height: 45px;
  231. "
  232. >
  233. {{ productInfo.product_name }}
  234. <br />
  235. By {{ getFreightType(row) }}&nbsp;-&nbsp;{{
  236. exportForm[`zdy_date_${row.typeNumber}_${row.number}`]
  237. }}{{
  238. exportForm[`cycle_name_${row.typeNumber}_${row.number}`]
  239. }}
  240. </td>
  241. <td style="border-bottom: solid 1px #ccc; height: 45px">
  242. {{ formatNumber(row.number, true) }}&nbsp;units
  243. </td>
  244. <td style="border-bottom: solid 1px #ccc; height: 45px">
  245. ${{ formatNumber(row.setup_cost)
  246. }}{{ exportForm.gst_name ? '+GST' : '' }}
  247. </td>
  248. <td style="border-bottom: solid 1px #ccc; height: 45px">
  249. ${{ formatNumber(row.sold_unit)
  250. }}{{ exportForm.gst_name ? '+GST' : '' }}
  251. </td>
  252. <td style="border-bottom: solid 1px #ccc; height: 45px">
  253. ${{ formatNumber(row.add_freight_cost)
  254. }}{{ exportForm.gst_name ? '+GST' : '' }}
  255. </td>
  256. <td style="border-bottom: solid 1px #ccc; height: 45px">
  257. ${{ formatNumber(row.sold_price)
  258. }}{{ exportForm.gst_name ? '+GST' : '' }}
  259. </td>
  260. </tr>
  261. <tr>
  262. <td
  263. colspan="7"
  264. style="text-align: left; line-height: 45px"
  265. >
  266. Freight to {{ city_short[city] || city }} is included.Price
  267. based on exchange rate of {{ exportForm.exchange }}.Price is
  268. only valid for {{ exportForm.days }} days.
  269. </td>
  270. </tr>
  271. </tbody>
  272. </table>
  273. </td>
  274. </tr>
  275. <tr>
  276. <td colspan="2">
  277. <p style="line-height: 45px">
  278. <strong style="border-bottom: dashed 2px #000; padding: 10px">
  279. Notes
  280. </strong>
  281. </p>
  282. </td>
  283. </tr>
  284. <tr>
  285. <td colspan="2">
  286. <p style="padding-top: 20px" v-html="exportForm.notes.replace(/\n/g, '<br>')"></p>
  287. </td>
  288. </tr>
  289. <tr>
  290. <td colspan="2">
  291. <p style="padding-top: 20px">
  292. <img
  293. v-for="(item, index) in otherPicture"
  294. :key="index"
  295. :src="item"
  296. width="250px"
  297. style="padding-right: 10px"
  298. />
  299. </p>
  300. </td>
  301. </tr>
  302. <tr>
  303. <td colspan="2">
  304. <p>
  305. <a :href="mainPicture">{{ mainPicture }}</a>
  306. </p>
  307. </td>
  308. </tr>
  309. <tr>
  310. <td colspan="2">
  311. <p
  312. v-for="p in otherPicture"
  313. :key="p"
  314. >
  315. <a
  316. :href="p"
  317. target="_blank"
  318. >
  319. {{ p }}
  320. </a>
  321. </p>
  322. </td>
  323. </tr>
  324. <tr>
  325. <td
  326. colspan="2"
  327. style="text-align: center"
  328. >
  329. <img
  330. style="margin-top: 10px"
  331. src="http://zohocrmapi.promocollection.com.au/static/uploads/logo/pdf_end.png"
  332. />
  333. </td>
  334. </tr>
  335. </tbody>
  336. </table>
  337. </div>
  338. </template>
  339. <script lang="ts" setup>
  340. import { defineComponent, computed } from 'vue'
  341. import jspdf from 'jspdf'
  342. import html2canvas from 'html2canvas'
  343. import dayjs from 'dayjs'
  344. import { downloadPDF } from '@/api/indent'
  345. defineComponent({
  346. name: 'ComponentExportQuota2',
  347. })
  348. const {
  349. city = '',
  350. city2 = '',
  351. productInfo = {} as any,
  352. exportForm = {} as any,
  353. step2FormList = [],
  354. step3FormList = [],
  355. creatorOptions = [],
  356. } = defineProps<{
  357. city: string
  358. city2: string
  359. productInfo: object
  360. exportForm: object
  361. step2FormList: any[]
  362. step3FormList: any[]
  363. creatorOptions: any[]
  364. }>()
  365. const city_short = {
  366. SYD: 'Sydney',
  367. Melb: 'Melbourne',
  368. Brisbane: 'Brisbane',
  369. SA: 'Adelaide',
  370. WA: 'Perth',
  371. US: 'US',
  372. '': '',
  373. } as any
  374. const getLogoPath = () => {
  375. return new URL('/assets/logo.png', import.meta.url).href
  376. }
  377. const getFreightType = (row: any) => {
  378. let result = 'Sea'
  379. if (row.typeNumber < 2) {
  380. result = 'Air'
  381. }
  382. if (row.typeNumber === 3) {
  383. const temp: any[] = step2FormList.filter(
  384. (i: any) => i.number === row.number,
  385. )
  386. if (
  387. temp.length &&
  388. temp[0].fclData?.method_fcl &&
  389. ['快递', '空运'].includes(temp[0].fclData.method_fcl)
  390. ) {
  391. result = 'Air'
  392. }
  393. }
  394. return result
  395. }
  396. const generatePDF = () => {
  397. downloadPDF({
  398. content: document.getElementById('pdfTarget')?.outerHTML,
  399. title: productInfo.product_name || '_',
  400. create_time: '_',
  401. }).then((res: any) => {
  402. console.log(res, 'res pdf')
  403. if (res.result?.length) {
  404. window.open(import.meta.env.VITE_API_PREFIX + '/' + res.result)
  405. }
  406. })
  407. }
  408. // 把这个方法暴露给父组件, 否则无法在父组件被调用
  409. defineExpose({ generatePDF })
  410. const shouldSplit = (
  411. nodes: HTMLElement[],
  412. index: number,
  413. pageHeight: number,
  414. ) => {
  415. // 计算当前这块dom是否跨越了a4大小,以此分割
  416. // console.log(index, 'index start')
  417. if (
  418. nodes[index].offsetTop + nodes[index].clientHeight < pageHeight &&
  419. nodes[index + 1] &&
  420. nodes[index + 1].offsetTop + nodes[index + 1].clientHeight > pageHeight
  421. ) {
  422. return true
  423. }
  424. return false
  425. }
  426. const mainPicture = computed(() => {
  427. if (
  428. Array.isArray(productInfo.product_image) &&
  429. productInfo.product_image.length
  430. ) {
  431. return productInfo.product_image[0]
  432. }
  433. return ''
  434. })
  435. const otherPicture = computed(() => {
  436. if (
  437. Array.isArray(productInfo.product_image) &&
  438. productInfo.product_image.length > 1
  439. ) {
  440. return productInfo.product_image.slice(1)
  441. }
  442. return []
  443. })
  444. const computedCreator = computed(() => {
  445. let result = ''
  446. if (creatorOptions.length) {
  447. const a: any[] = creatorOptions.filter(
  448. (i: any) => i.value === exportForm.saleperson,
  449. )
  450. if (a.length) result = a[0].label
  451. }
  452. return result
  453. })
  454. // 处理数字, 保留两位小数, 即使是整数也显示两位00, 每3位用英文逗号分割
  455. const formatNumber = (number: number, no00 = false) => {
  456. const num = Number(number)
  457. if (Number.isNaN(num)) return '0.00'
  458. return no00
  459. ? `${num}`.replace(/\B(?=(\d{3})+(?!\d))/g, ',')
  460. : num.toFixed(2).replace(/\B(?=(\d{3})+(?!\d))/g, ',')
  461. }
  462. </script>
  463. <style lang="scss" scoped>
  464. $subColor: #777;
  465. .pdf-wrap {
  466. // position: fixed;
  467. top: 0;
  468. left: 0;
  469. // z-index: 9999;
  470. // top: -9999px;
  471. // right: -9999px;
  472. box-sizing: border-box;
  473. width: 21cm;
  474. margin: 0 auto 12px;
  475. box-shadow: 1px 1px 2pt 0px $subColor;
  476. }
  477. </style>