index.vue 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213
  1. <template>
  2. <view class="createCode" v-if="isShow" @click.stop="isShow=false">
  3. <view class="content">
  4. <canvas :style="{ width: canvasW + 'px', height: canvasH + 'px' }" canvas-id="my-canvas"></canvas>
  5. <view class="save-btn" @click.stop="saveImage" v-if="!isLoading">保存图片</view>
  6. </view>
  7. <canvas :style="{ width: canvasW * 2 + 'px', height: canvasH * 2 + 'px' }" canvas-id="big-canvas" class="big-canvas"></canvas>
  8. </view>
  9. </template>
  10. <script>
  11. import { post } from "@/request/api.js";
  12. export default {
  13. props: {},
  14. data() {
  15. return {
  16. canvasW: 0,
  17. canvasH: 0,
  18. ctx: null,
  19. isShow: false,
  20. isLoading: true,
  21. title: "草莓千层蛋糕",
  22. qrcode: 'https://oss.zhangyubk.com/cmqrcode.jpg',
  23. headerImg: "https://teaclub.oss-cn-chengdu.aliyuncs.com/CloudShop/head_pic/268c896c47298c7c79a8270c36076741e8f15b0fjpg"
  24. }
  25. },
  26. methods: {
  27. //显示
  28. showCanvas(da) {
  29. this.isShow = true
  30. this.title = da.name
  31. this.isLoading = true
  32. uni.showLoading({ title: '加载中...', mask: true })
  33. this.getQrcode(da)
  34. },
  35. // 获取商家码
  36. async getQrcode(da){
  37. let res = await post("v1/merchant/xcxqrcode",da)
  38. if(res.code == 0) {
  39. console.log(res.data);
  40. this.qrcode = res.data;
  41. this.__init()
  42. }
  43. },
  44. //初始化画布
  45. async __init() {
  46. this.ctx = uni.createCanvasContext('my-canvas', this)
  47. this.bigCtx = uni.createCanvasContext('big-canvas', this)
  48. this.canvasW = uni.upx2px(600);
  49. this.canvasH = uni.upx2px(820);
  50. //设置画布背景透明
  51. this.ctx.setFillStyle('rgba(255, 255, 255, 0)')
  52. this.bigCtx.setFillStyle('rgba(255, 255, 255, 0)')
  53. //设置画布大小
  54. this.ctx.fillRect(0, 0, this.canvasW, this.canvasH)
  55. this.bigCtx.fillRect(0, 0, this.canvasW * 2, this.canvasH * 2)
  56. //绘制圆角背景
  57. this.drawRoundRect(this.ctx, 0, 0, this.canvasW, this.canvasH, uni.upx2px(18), '#FFFFFF')
  58. this.drawRoundRect(this.bigCtx, 0, 0, this.canvasW * 2, this.canvasH * 2, uni.upx2px(36), '#FFFFFF')
  59. //获取标题图片
  60. let headerImg = await this.getImageInfo(this.headerImg)
  61. //绘制标题图
  62. this.drawRoundImg(this.ctx, headerImg.path, 0, 0, this.canvasW, this.canvasH, 8)
  63. this.drawRoundImg(this.bigCtx, headerImg.path, 0, 0, this.canvasW * 2, this.canvasH * 2, 16)
  64. //绘制标题
  65. this.ctx.setFontSize(14); //设置标题字体大小
  66. this.ctx.setFillStyle('#333'); //设置标题文本颜色
  67. this.ctx.textAlign = 'center';
  68. this.ctx.fillText(this.title, (this.canvasW / 2), (this.canvasH - uni.upx2px(275)))
  69. this.bigCtx.setFontSize(28); //设置标题字体大小
  70. this.bigCtx.setFillStyle('#333'); //设置标题文本颜色
  71. this.bigCtx.textAlign = 'center';
  72. this.bigCtx.fillText(this.title, this.canvasW, (this.canvasH * 2 - uni.upx2px(275 * 2)))
  73. //小程序码
  74. let qrH = uni.upx2px(316);
  75. let qrcodeImg = await this.getImageInfo(this.qrcode)
  76. this.ctx.drawImage(qrcodeImg.path, ((this.canvasW - qrH) / 2), uni.upx2px(190), qrH, qrH)
  77. this.bigCtx.drawImage(qrcodeImg.path, this.canvasW - qrH, uni.upx2px(190 * 2), qrH * 2, qrH * 2)
  78. //延迟渲染
  79. setTimeout(() => {
  80. this.ctx.draw(true, () => {
  81. this.isLoading = false
  82. uni.hideLoading()
  83. })
  84. this.bigCtx.draw(true, () => {})
  85. }, 500)
  86. },
  87. //带圆角图片
  88. drawRoundImg(ctx, img, x, y, width, height, radius) {
  89. ctx.beginPath()
  90. ctx.save()
  91. // 左上角
  92. ctx.arc(x + radius, y + radius, radius, Math.PI, Math.PI * 1.5)
  93. // 右上角
  94. ctx.arc(x + width - radius, y + radius, radius, Math.PI * 1.5, Math.PI * 2)
  95. // 右下角
  96. ctx.arc(x + width - radius, y + height - radius, radius, 0, Math.PI * 0.5)
  97. // 左下角
  98. ctx.arc(x + radius, y + height - radius, radius, Math.PI * 0.5, Math.PI)
  99. ctx.stroke()
  100. ctx.clip()
  101. ctx.drawImage(img, x, y, width, height);
  102. ctx.restore()
  103. ctx.closePath()
  104. },
  105. //圆角矩形
  106. drawRoundRect(ctx, x, y, width, height, radius, color) {
  107. ctx.save();
  108. ctx.beginPath();
  109. ctx.setFillStyle(color);
  110. ctx.setStrokeStyle(color)
  111. ctx.setLineJoin('round'); //交点设置成圆角
  112. ctx.setLineWidth(radius);
  113. ctx.strokeRect(x + radius / 2, y + radius / 2, width - radius, height - radius);
  114. ctx.fillRect(x + radius, y + radius, width - radius * 2, height - radius * 2);
  115. ctx.stroke();
  116. ctx.closePath();
  117. },
  118. //获取图片
  119. getImageInfo(imgSrc) {
  120. return new Promise((resolve, reject) => {
  121. uni.getImageInfo({
  122. src: imgSrc,
  123. success: (image) => {
  124. resolve(image);
  125. console.log('获取图片成功', image)
  126. },
  127. fail: (err) => {
  128. reject(err);
  129. console.log('获取图片失败', err)
  130. }
  131. });
  132. });
  133. },
  134. //保存图片到相册
  135. saveImage() {
  136. var that = this
  137. //判断用户授权
  138. uni.getSetting({
  139. success(res) {
  140. console.log('获取用户权限', res.authSetting)
  141. let wpa = res.authSetting['scope.writePhotosAlbum']
  142. //判断是否有相册权限
  143. if (wpa == undefined) that.runSave()
  144. else if (!wpa) { //打开设置权限
  145. uni.openSetting({
  146. success(res) {
  147. console.log('设置权限', res.authSetting)
  148. if(res.authSetting['scope.writePhotosAlbum']) that.runSave()
  149. }
  150. })
  151. }
  152. else that.runSave()
  153. }
  154. })
  155. },
  156. runSave(){
  157. var that = this
  158. uni.canvasToTempFilePath({
  159. canvasId: 'big-canvas',
  160. quality: 1,
  161. complete: (res) => {
  162. console.log('保存到相册', res);
  163. uni.saveImageToPhotosAlbum({
  164. filePath: res.tempFilePath,
  165. success(res) {
  166. uni.showToast({
  167. title: '已保存到相册',
  168. icon: 'success',
  169. duration: 2000
  170. })
  171. setTimeout(() => {
  172. that.isShow = false
  173. }, 2000)
  174. }
  175. })
  176. }
  177. }, this);
  178. }
  179. }
  180. }
  181. </script>
  182. <style scoped lang="scss">
  183. .createCode{
  184. position: fixed;
  185. top: 0;
  186. left: 0;
  187. width: 100%;
  188. min-height: 100vh;
  189. overflow: hidden;
  190. }
  191. .content {
  192. background: rgba(0, 0, 0, .4);
  193. display: flex;
  194. flex-direction: column;
  195. justify-content: center;
  196. align-items: center;
  197. z-index: 100;
  198. padding: 100rpx 0;
  199. min-height: 100vh;
  200. .save-btn {
  201. margin-top: 35rpx;
  202. color: #FFFFFF;
  203. background: linear-gradient(to right, #018C39, #00B147);
  204. padding: 15rpx 40rpx;
  205. border-radius: 50rpx;
  206. }
  207. }
  208. .big-canvas{
  209. opacity: 0;
  210. z-index: 0;
  211. }
  212. </style>