index.vue 12 KB

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