invite.vue 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277
  1. <template>
  2. <view>
  3. <!--promote/invite/invite.wxml-->
  4. <image
  5. :src="config.Distribution_Poster_Background ? config.Distribution_Poster_Background+ '?x-oss-process=style/w750-auto' : picUrlss+'fenxiaobg.jpg'"
  6. mode="widthFix" class="bgimg"></image>
  7. <view class="invite">
  8. <view class="logo dflex">
  9. <image :src="config.CONFIG_PROJECT_LOGO" mode="aspectFit" class="logoimg"></image>
  10. <view class="flex">{{config.CONFIG_PROJECT_TITLE}}</view>
  11. </view>
  12. </view>
  13. <view class="bot">
  14. <view class="code">
  15. <image :src="codeUrl"></image>
  16. </view>
  17. <view class="btn">
  18. <view class="share" @tap="saveImage">保存到相册</view>
  19. </view>
  20. </view>
  21. <canvas canvas-id="invite" class="canvas" style="width:414px;height:827px;"></canvas>
  22. </view>
  23. </template>
  24. <script>
  25. // promote/invite/invite.js
  26. const app = getApp();
  27. const utils = require("../../utils/util.js");
  28. const req = require("../../utils/request.js");
  29. export default {
  30. data() {
  31. return {
  32. picUrlss: req.public.picUrls,
  33. config: {},
  34. codeUrl: '',
  35. imgUrl: ''
  36. };
  37. },
  38. components: {},
  39. props: {},
  40. onLoad: async function(options) {
  41. await this.getCodeUrl();
  42. await this.getConfig();
  43. await this.generatePoster();
  44. },
  45. methods: {
  46. getConfig() {
  47. var _this = this;
  48. return new Promise((resolve, reject) => {
  49. req.g('/api/config', res => {
  50. // console.log('配置数据====' + JSON.stringify(res));
  51. _this.setData({
  52. config: res
  53. });
  54. resolve();
  55. }, true);
  56. });
  57. },
  58. getCodeUrl() {
  59. let that = this; //获取小程序码
  60. const params = {
  61. // page: 'pages/index/index',
  62. page: 'pages/authorize/authorize',
  63. scene: req.getStorage('userInfo').id + '_' + 'isPromote'
  64. };
  65. return new Promise((resolve, reject) => {
  66. req.getRequest('/api/program/codev', params, url => {
  67. // console.log(url);
  68. that.setData({
  69. codeUrl: url
  70. });
  71. resolve();
  72. });
  73. });
  74. },
  75. generatePoster() {
  76. let that = this;
  77. that.generate(imgUrl => {
  78. that.setData({
  79. imgUrl: imgUrl
  80. });
  81. });
  82. },
  83. isAuth(fun) {
  84. if (!uni.saveImageToPhotosAlbum) {
  85. uni.showModal({
  86. title: '提示',
  87. content: '当前微信版本过低,无法使用该功能,请升级到最新微信版本后重试。'
  88. });
  89. return;
  90. }
  91. ; //可以通过 wx.getSetting 先查询一下用户是否授权了 "scope.writePhotosAlbum" 这个 scope
  92. // #ifndef H5
  93. uni.getSetting({
  94. success(res) {
  95. // console.log(res);
  96. if (!res.authSetting['scope.writePhotosAlbum']) {
  97. // 接口调用询问
  98. uni.authorize({
  99. scope: 'scope.writePhotosAlbum',
  100. success() {
  101. // console.log("2-授权《保存图片》权限成功");
  102. fun(true);
  103. },
  104. fail() {
  105. fun(false);
  106. }
  107. });
  108. } else {
  109. // 拒绝授权
  110. fun(true);
  111. }
  112. },
  113. fail(res) {
  114. fun(false);
  115. }
  116. });
  117. // #endif
  118. },
  119. saveImage() {
  120. let that = this;
  121. that.isAuth(success => {
  122. if (success) {
  123. // console.log("图片地址=====" + that.imgUrl);
  124. uni.saveImageToPhotosAlbum({
  125. filePath: that.imgUrl,
  126. success(res) {
  127. uni.showToast({
  128. title: '图片保存成功',
  129. icon: 'none',
  130. success() {},
  131. fail() {
  132. uni.showToast({
  133. title: '图片保存失败'
  134. });
  135. }
  136. });
  137. }
  138. });
  139. }
  140. });
  141. },
  142. getImageInfo(url) {
  143. return new Promise((resolve, reject) => {
  144. if (!url) {
  145. resolve();
  146. return false;
  147. }
  148. uni.getImageInfo({
  149. src: url,
  150. success: resolve,
  151. fail: reject
  152. });
  153. });
  154. },
  155. generate(success) {
  156. // 获取商品图片
  157. const picPromise = this.getImageInfo(this.config.Distribution_Poster_Background);
  158. const avatarPromise = this.getImageInfo(this.config.CONFIG_PROJECT_LOGO); // 获取小程序码图
  159. const codePromise = this.getImageInfo(this.codeUrl);
  160. let that = this;
  161. Promise.all([picPromise, avatarPromise, codePromise]).then(([pic, avatar, code]) => {
  162. // 创建绘图上下文
  163. const ctx = uni.createCanvasContext('invite', this); // 绘制背景,填充满整个canvas画布
  164. let width = 414,
  165. height = 827; //默认背景
  166. ctx.drawImage(pic ? pic.path : picUrlss+'fenxiaobg.jpg', 0, 0, width,
  167. height); //白色背景
  168. ctx.save();
  169. that.roundRect(ctx, 137, 585, 140, 140, 10);
  170. ctx.restore();
  171. ctx.drawImage(code.path, 147, 595, 120, 120);
  172. ctx.fillStyle = '#fff';
  173. ctx.font = "16px PingFang SC";
  174. ctx.fillText(that.config.CONFIG_PROJECT_TITLE, 65, 40); //logo
  175. ctx.save();
  176. ctx.beginPath();
  177. ctx.arc(35, 35, 20, 0, 2 * Math.PI, true); //画一个圆形裁剪区域
  178. ctx.clip(); //裁剪
  179. ctx.drawImage(avatar.path, 15, 15, 40, 40); //绘制图片
  180. // 完成作画
  181. ctx.draw(false, function() {
  182. uni.canvasToTempFilePath({
  183. canvasId: 'invite',
  184. success: function(res) {
  185. success.call(this, res.tempFilePath);
  186. },
  187. fail: function(res) {
  188. // console.log(res);
  189. }
  190. }, that);
  191. });
  192. });
  193. },
  194. /**
  195. *
  196. * @param {CanvasContext} ctx canvas上下文
  197. * @param {number} x 圆角矩形选区的左上角 x坐标
  198. * @param {number} y 圆角矩形选区的左上角 y坐标
  199. * @param {number} w 圆角矩形选区的宽度
  200. * @param {number} h 圆角矩形选区的高度
  201. * @param {number} r 圆角的半径
  202. */
  203. roundRect: function(ctx, x, y, w, h, r) {
  204. // 开始绘制
  205. ctx.beginPath(); // 因为边缘描边存在锯齿,最好指定使用 transparent 填充
  206. // 这里是使用 fill 还是 stroke都可以,二选一即可
  207. ctx.setFillStyle('white'); // ctx.setStrokeStyle('transparent')
  208. // 左上角
  209. ctx.arc(x + r, y + r, r, Math.PI, Math.PI * 1.5); // border-top
  210. ctx.moveTo(x + r, y);
  211. ctx.lineTo(x + w - r, y);
  212. ctx.lineTo(x + w, y + r); // 右上角
  213. ctx.arc(x + w - r, y + r, r, Math.PI * 1.5, Math.PI * 2); // border-right
  214. ctx.lineTo(x + w, y + h - r);
  215. ctx.lineTo(x + w - r, y + h); // 右下角
  216. ctx.arc(x + w - r, y + h - r, r, 0, Math.PI * 0.5); // border-bottom
  217. ctx.lineTo(x + r, y + h);
  218. ctx.lineTo(x, y + h - r); // 左下角
  219. ctx.arc(x + r, y + h - r, r, Math.PI * 0.5, Math.PI); // border-left
  220. ctx.lineTo(x, y + r);
  221. ctx.lineTo(x + r, y); // 这里是使用 fill 还是 stroke都可以,二选一即可,但是需要与上面对应
  222. ctx.fill(); // ctx.stroke()
  223. ctx.closePath(); // 剪切
  224. ctx.clip();
  225. }
  226. }
  227. };
  228. </script>
  229. <style>
  230. @import "./invite.css";
  231. </style>