invitePoster.vue 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461
  1. <template>
  2. <view class="invitePoster-box">
  3. <GloableLoading />
  4. <view class="poster-box flex-items-plus flex-column">
  5. <image class="header-img mar-top-10" :src="data.headImage"></image>
  6. <label class="mar-top-30">发现一件好物,快来和我一起拼</label>
  7. <image class="poster-img mar-top-50" :src="data.image"></image>
  8. <view class="flex-row-plus flex-sp-between mar-top-40">
  9. <view class="flex-column-plus">
  10. <label class="title-lab fs28">{{ data.productName }}</label>
  11. <view class="spellNum flex-items-plus font-color-C5AA7B mar-top-30 fs24">{{ data.person }}人团</view>
  12. <view class="flex-row-plus mar-top-20 flex-items">
  13. <label class="font-color-C5AA7B fs24">¥</label>
  14. <label class="font-color-C5AA7B fs36 mar-left-5">{{ data.price }}</label>
  15. <label class="font-color-999 fs26 mar-left-20">原价:¥{{ data.originalPrice }}</label>
  16. </view>
  17. </view>
  18. <view class="flex-column-plus flex-items-plus">
  19. <image style="width: 180upx;height: 180upx;" :src="qrcode"></image>
  20. <label class="font-color-666">扫描二维码</label>
  21. </view>
  22. </view>
  23. <!-- #ifndef H5 -->
  24. <view class="saveposter-but flex-items-plus mar-top-50" @click="savePoster(1)">
  25. 保存海报
  26. </view>
  27. <!-- #endif -->
  28. <!-- #ifdef H5 -->
  29. <view class="saveposter-but flex-items-plus mar-top-50" @click="savePoster(2)">
  30. 预览海报
  31. </view>
  32. <!-- #endif -->
  33. </view>
  34. <view class="bor-reu-8 pad-bot-30 canvas-box">
  35. <canvas id="posterCanvas" style="width: 375px; height: 560px;" canvas-id="posterCanvas"></canvas>
  36. </view>
  37. </view>
  38. </template>
  39. <script>
  40. import GloableLoading from '../../components/diyLoading'
  41. import { base64ToPath } from 'image-tools'
  42. const NET = require('../../utils/request')
  43. const API = require('../../config/api')
  44. export default {
  45. components: { GloableLoading },
  46. data() {
  47. return {
  48. data: {},
  49. canvasWidth: 0,
  50. codeImg: '',
  51. codeImg2: '',
  52. headImage: '',
  53. image: '',
  54. qrcode: '',
  55. qrcodeimg: '',
  56. loadingQrcode: true
  57. }
  58. },
  59. onLoad(options) {
  60. this.data = JSON.parse(options.data)
  61. this.getShare()
  62. },
  63. methods: {
  64. savePoster(type) {
  65. if (this.loadingQrcode) {
  66. uni.showToast({
  67. icon: 'none',
  68. title: '请稍等,正在生成二维码...'
  69. })
  70. return
  71. }
  72. this.$showLoading()
  73. if (type == 1) {
  74. // uni.showLoading({
  75. // mask: true,
  76. // title:"生成图片中..."
  77. // })
  78. const that = this
  79. setTimeout(() => {
  80. // #ifdef H5 || MP-WEIXIN || APP-PLUS
  81. uni.canvasToTempFilePath({ // 把画布转化成临时文件进行保存
  82. fileType: 'png', // 保存成的文件类型
  83. quality: 0, // 图片质量
  84. canvasId: 'posterCanvas', // 画布ID
  85. success: (res) => {
  86. this.$hideLoading()
  87. that.saveDownload(res.tempFilePath)
  88. },
  89. fail: () => {
  90. uni.showToast({
  91. title: '保存失败,稍后再试',
  92. duration: 2000,
  93. icon: 'none'
  94. })
  95. this.$hideLoading()
  96. // uni.hideLoading();
  97. }
  98. })
  99. // #endif
  100. // #ifdef MP-ALIPAY
  101. const CanvasContext = my.createCanvasContext('posterCanvas')
  102. CanvasContext.toTempFilePath({
  103. success: (res) => {
  104. my.saveImage({
  105. url: res.apFilePath,
  106. success: (res) => {
  107. // uni.hideLoading();
  108. this.$hideLoading()
  109. uni.showToast({
  110. title: '图片保存成功~',
  111. duration: 2000
  112. })
  113. },
  114. fail: (err) => {
  115. this.$hideLoading()
  116. console.error('saveImage err', err)
  117. }
  118. })
  119. },
  120. fail: () => {
  121. this.$hideLoading()
  122. uni.showToast({
  123. title: '保存失败,稍后再试',
  124. duration: 2000,
  125. icon: 'none'
  126. })
  127. // uni.hideLoading();
  128. }
  129. })
  130. // #endif
  131. }, 5000)
  132. } else if (type == 2) {
  133. // uni.showLoading({
  134. // mask: true,
  135. // title:"图片生成中..."
  136. // })
  137. const that = this
  138. setTimeout(() => {
  139. uni.canvasToTempFilePath({ // 把画布转化成临时文件进行保存
  140. fileType: 'png', // 保存成的文件类型
  141. quality: 0, // 图片质量
  142. canvasId: 'posterCanvas', // 画布ID
  143. success: (res) => {
  144. uni.downloadFile({
  145. url: res.tempFilePath, // 网络路径,下载下来
  146. success: (res1) => {
  147. this.$hideLoading()
  148. if (res1.statusCode === 200) {
  149. // uni.hideLoading();
  150. uni.showModal({
  151. title: '提示',
  152. content: '长按即可保存图片',
  153. confirmText: '确定',
  154. cancelText: '取消',
  155. success: (res) => {
  156. if (res.confirm) {
  157. uni.previewImage({
  158. current: res1.tempFilePath, // 当前显示图片的http链接
  159. urls: [ res1.tempFilePath ] // 需要预览的图片http链接列表
  160. })
  161. }
  162. }
  163. })
  164. }
  165. }
  166. })
  167. },
  168. fail: (err) => {
  169. this.$hideLoading()
  170. uni.showToast({
  171. title: '保存失败,稍后再试',
  172. duration: 2000,
  173. icon: 'none'
  174. })
  175. }
  176. })
  177. }, 5000)
  178. }
  179. },
  180. saveDownload(file) {
  181. const that = this
  182. // uni.showLoading({
  183. // mask: true,
  184. // title:"图片保存中..."
  185. // })
  186. this.$showLoading()
  187. uni.getImageInfo({
  188. src: file,
  189. success: (res1) => {
  190. // 2-保存图片至相册
  191. uni.saveImageToPhotosAlbum({ // 存成图片至手机
  192. filePath: res1.path, // 画布保存的图片临时文件
  193. success: (res2) => {
  194. this.$hideLoading()
  195. // uni.hideLoading();
  196. uni.showToast({
  197. title: '图片保存成功~',
  198. duration: 2000
  199. })
  200. },
  201. fail: (res3) => {
  202. this.$hideLoading()
  203. if (res3.errMsg === 'saveImageToPhotosAlbum:fail auth deny') {
  204. // that.$store.dispatch('SetPhoneShow', 1)
  205. uni.showToast({
  206. title: '保存失败,请检查是否授权小程序保存图片!',
  207. duration: 3000,
  208. icon: 'none'
  209. })
  210. } else {
  211. uni.showToast({
  212. title: '保存失败,稍后再试',
  213. duration: 2000,
  214. icon: 'none'
  215. })
  216. }
  217. // uni.hideLoading();
  218. }
  219. })
  220. }
  221. })
  222. },
  223. getShare() {
  224. NET.request(
  225. API.getShare,
  226. {
  227. collageId: this.data.collageId,
  228. orderId: this.data.orderId,
  229. productId: this.data.productId,
  230. skuId: this.data.skuId,
  231. type: 0
  232. },
  233. 'GET'
  234. ).then((res) => {
  235. // #ifndef MP-WEIXIN
  236. this.qrcode = res.data.qrcode
  237. // #endif
  238. // #ifdef MP-WEIXIN
  239. this.qrcode = res.data.xcxQrcode
  240. // #endif
  241. this.getCanvas()
  242. this.loadingQrcode = false
  243. })
  244. .catch((res) => {
  245. })
  246. },
  247. getCanvas() {
  248. const that = this
  249. // #ifndef MP-WEIXIN
  250. uni.getImageInfo({
  251. src: that.data.headImage,
  252. success(image) {
  253. that.headImage = image.path
  254. uni.getImageInfo({
  255. src: that.data.image,
  256. success(image2) {
  257. that.image = image2.path
  258. uni.getImageInfo({
  259. src: that.qrcode,
  260. success(image3) {
  261. that.qrcodeimg = image3.path
  262. setTimeout(() => {
  263. var ctx = uni.createCanvasContext('posterCanvas')
  264. ctx.setFillStyle('#FFFFFF')
  265. ctx.fillRect(0, 0, 375, 560)
  266. // ctx.drawImage(that.data.headImage, 0, 0, 150, 100)
  267. that.drawRound(ctx, 25, 160, 28, that.headImage)
  268. ctx.setFontSize(14)
  269. ctx.setFillStyle('#333333')
  270. ctx.fillText('发现一件好物,快来和我一起拼', 89, 120)
  271. ctx.drawImage(that.image, 25, 150, 310, 200)
  272. ctx.setFontSize(14)
  273. ctx.setFillStyle('#333333')
  274. ctx.fillText(that.data.productName, 40, 390)
  275. ctx.setFontSize(14)
  276. ctx.setFillStyle('#C5AA7B')
  277. ctx.fillText(that.data.person + '人团', 40, 430)
  278. ctx.setFontSize(24)
  279. ctx.setFillStyle('#C5AA7B')
  280. ctx.fillText('¥' + that.data.price, 40, 470)
  281. ctx.setFontSize(14)
  282. ctx.setFillStyle('#999999')
  283. ctx.fillText('原价:¥' + that.data.originalPrice, 120, 468)
  284. ctx.drawImage(that.qrcodeimg, 245, 370, 80, 80)
  285. ctx.setFontSize(14)
  286. ctx.setStrokeStyle('#666666')
  287. ctx.fillText('扫描二维码', 250, 468)
  288. ctx.draw()
  289. }, 1500)
  290. }
  291. })
  292. }
  293. })
  294. }
  295. })
  296. // #endif
  297. // #ifdef MP-WEIXIN
  298. uni.getImageInfo({
  299. src: that.data.image,
  300. success(image2) {
  301. that.image = image2.path
  302. uni.getImageInfo({
  303. src: that.qrcode,
  304. success(image3) {
  305. that.qrcodeimg = image3.path
  306. setTimeout(() => {
  307. var ctx = uni.createCanvasContext('posterCanvas')
  308. ctx.setFillStyle('#FFFFFF')
  309. ctx.fillRect(0, 0, 375, 560)
  310. // ctx.drawImage(that.data.headImage, 0, 0, 150, 100)
  311. // that.drawRound(ctx, 25, 160, 28, that.headImage)
  312. ctx.setFontSize(14)
  313. ctx.setFillStyle('#333333')
  314. ctx.fillText('发现一件好物,快来和我一起拼', 89, 120)
  315. ctx.drawImage(that.image, 25, 150, 310, 200)
  316. ctx.setFontSize(14)
  317. ctx.setFillStyle('#333333')
  318. let newStr = ''; let startPartIndex = 0
  319. for (let i = 0; i < that.data.productName.length; i++) {
  320. if (i % 14 === 0) {
  321. newStr += that.data.productName.slice(startPartIndex, i) + '\n'
  322. startPartIndex = i
  323. }
  324. if (i === that.data.productName.length - 1) newStr += that.data.productName.slice(startPartIndex)
  325. }
  326. const productNameArr = newStr.split('\n').filter((item) => item)
  327. productNameArr.forEach((productNameItem, productNameIndex) => {
  328. const y = 390 + (productNameIndex * 22)
  329. ctx.fillText(productNameItem, 40, y)
  330. })
  331. ctx.setFontSize(14)
  332. ctx.setFillStyle('#C5AA7B')
  333. ctx.fillText(that.data.person + '人团', 40, 430 + ((productNameArr.length - 1) * 22))
  334. ctx.setFontSize(24)
  335. ctx.setFillStyle('#C5AA7B')
  336. ctx.fillText('¥' + that.data.price, 40, 470 + ((productNameArr.length - 1) * 22))
  337. ctx.setFontSize(14)
  338. ctx.setFillStyle('#999999')
  339. ctx.fillText('原价:¥' + that.data.originalPrice, 120, 468 + ((productNameArr.length - 1) * 22))
  340. ctx.drawImage(that.qrcodeimg, 245, 370 + (productNameArr.length - 1) * 22, 80, 80)
  341. ctx.setFontSize(14)
  342. ctx.setStrokeStyle('#666666')
  343. ctx.fillText('扫描二维码', 250, 468 + (productNameArr.length - 1) * 22)
  344. ctx.draw()
  345. }, 1500)
  346. }
  347. })
  348. }
  349. })
  350. // #endif
  351. },
  352. exportImg() {
  353. uni.canvasToTempFilePath({
  354. fileType: 'jpg',
  355. canvasId: 'couponQrcode',
  356. success(res) {
  357. const that = this
  358. // 在H5平台下,tempFilePath 为 base64
  359. // #ifndef H5
  360. that.codeImg = res.tempFilePath
  361. // #endif
  362. // #ifdef H5
  363. base64ToPath(res.tempFilePath).then((path) => {
  364. that.codeImg = path
  365. })
  366. .catch((error) => {
  367. console.error(error)
  368. })
  369. // #endif
  370. }
  371. })
  372. },
  373. drawRound(ctx, r, x, y, img) {
  374. ctx.save() // 保存之前的
  375. var r = r // 半径*屏幕分辨率比例
  376. var d = 2 * r // 直径
  377. var cx = x + r // 圆弧坐标x
  378. var cy = y + r // 圆弧坐标 y
  379. ctx.arc(cx, cy, r, 0, 2 * Math.PI)
  380. ctx.clip() // 裁剪
  381. ctx.drawImage(img, x, y, d, d) // 画头像
  382. ctx.restore() // 返回上一状态
  383. }
  384. }
  385. }
  386. </script>
  387. <style lang="scss">
  388. .qrcode {
  389. padding: 0upx 0 20upx 0;
  390. display: flex;
  391. align-items: center;
  392. justify-content: center;
  393. }
  394. .title {
  395. text-align: center;
  396. }
  397. .canvas-box {
  398. position: absolute;
  399. top: -88888rpx;
  400. }
  401. page {
  402. background-color: #F7F7F7;
  403. }
  404. .invitePoster-box {
  405. .bor-reu-8 {
  406. border-radius: 8rpx;
  407. }
  408. .poster-box {
  409. background-color: #FFFFFF;
  410. margin: 30rpx 30rpx;
  411. width: 690rpx;
  412. padding: 40rpx 34rpx;
  413. border-radius: 8rpx;
  414. .header-img {
  415. width: 100rpx;
  416. height: 100rpx;
  417. border-radius: 50%;
  418. }
  419. .poster-img {
  420. width: 100%;
  421. height: 414rpx;
  422. }
  423. .title-lab {
  424. width: 400rpx;
  425. }
  426. .spellNum {
  427. background-color: #FFEDDF;
  428. border-radius: 22rpx;
  429. width: 144rpx;
  430. height: 44rpx;
  431. }
  432. .code-img {
  433. width: 142rpx;
  434. height: 142rpx;
  435. }
  436. .saveposter-but {
  437. border-radius: 5rpx;
  438. background-color: #C5AA7B;
  439. color: #FFFFFF;
  440. width: 420rpx;
  441. height: 66rpx;
  442. }
  443. }
  444. }
  445. </style>