posterService.vue 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313
  1. <template>
  2. <view>
  3. <view class="poster" id="poster">
  4. <image class="poster-pic" :src="posterBg" mode="widthFix"></image>
  5. <view class="ddflex" style="padding: 22rpx 35rpx;position: relative;">
  6. <view class="flex" v-if="typeCode=='poster'">
  7. <view class="poster-title">
  8. {{userInfo.realName?userInfo.realName:(userInfo.nickName?userInfo.nickName:'')}} | 中国人寿股份湖南分公司
  9. </view>
  10. <view class="poster-note">长按小程序码了解更多</view>
  11. </view>
  12. <view class="flex" v-if="typeCode=='poster_product'">
  13. <view class="poster-title">{{productTitle?productTitle:'请填写产品链接'}}</view>
  14. <view class="poster-note">长按二维码了解更多</view>
  15. </view>
  16. <image class="poster-code" :src="code?code:'../../static/images/lj_img.png'"></image>
  17. <view class="change-product ddflex" @click="jumpUrl('/library/productLink/productLink')"
  18. v-if="typeCode=='poster_product'">
  19. <image src="/static/images/edit1.png"></image>
  20. 产品链接
  21. </view>
  22. </view>
  23. </view>
  24. <view style="position: absolute;left: 9999px;top: -9999px;">
  25. <uqrcode v-if="typeCode=='poster_product'&&productLink" ref="uqrcode" canvas-id="qrcode"
  26. :value="productLink" :options="{ margin: 10 }" @complete='creatCode'></uqrcode>
  27. </view>
  28. <view style="height: 150rpx;"></view>
  29. <view class="share-btn">
  30. <view class="btn" @click="generatePoster">立即分享</view>
  31. </view>
  32. <canvas v-if="showCanvas" class="canvas" :style="'width:'+cwidth+'px;height:'+cheight+'px;'" canvas-id="share"></canvas>
  33. </view>
  34. </template>
  35. <script>
  36. const app = getApp();
  37. const req = require("../../utils/request.js");
  38. import utils from '../../utils/util.js'
  39. export default {
  40. components: {},
  41. props: {},
  42. data() {
  43. return {
  44. productTitle: '',
  45. productLink: '',
  46. posterBg: '',
  47. id: null,
  48. typeCode: '',
  49. code: '',
  50. userInfo: '',
  51. imgUrl:'',
  52. cwidth: 670,
  53. cheight: 1200,
  54. showCanvas:true
  55. }
  56. },
  57. watch:{
  58. productLink:{
  59. handler(newV,oldV){
  60. if(this.typeCode=='poster_product'){
  61. if(newV!=oldV){
  62. uni.showLoading({
  63. title:'二维码生成中'
  64. })
  65. }
  66. }
  67. }
  68. }
  69. },
  70. onLoad(options) {
  71. this.id = options.id
  72. this.typeCode = options.code
  73. this.userInfo = req.getStorage('userInfo')
  74. this.getPosterDetail()
  75. },
  76. onShow() {
  77. },
  78. methods: {
  79. jumpUrl(url) {
  80. uni.navigateTo({
  81. url: url
  82. })
  83. },
  84. // 获取海报详情
  85. getPosterDetail() {
  86. req.getRequest('/api/material/library/detail', {
  87. id: this.id
  88. }, res => {
  89. this.posterDetail = res
  90. this.posterBg = this.posterDetail.pic
  91. if (this.typeCode == 'poster') {
  92. this.getCodeUrl()
  93. }
  94. })
  95. },
  96. // 获取小程序码
  97. getCodeUrl() {
  98. let that = this; //获取小程序码
  99. let userInfo = req.getStorage('userInfo')
  100. const params = {
  101. page: 'pages/index/index',
  102. scene: userInfo.saleNo
  103. };
  104. return new Promise((resolve, reject) => {
  105. req.getRequest('/api/other/program/code', params, url => {
  106. this.code = url?url:'https://img.zhiqiyun.com/test/2023/08/28/170bb78d3cc86a35842e801aaeee991e.png'
  107. resolve();
  108. });
  109. });
  110. },
  111. creatCode() {
  112. this.$refs.uqrcode.toTempFilePath({
  113. success: res => {
  114. this.base64ToTempFilePath(res.tempFilePath.replace('data:image/png;base64,',''), (tempFilePath) => {
  115. this.code = tempFilePath
  116. uni.hideLoading()
  117. })
  118. // this.code = res.tempFilePath
  119. }
  120. });
  121. },
  122. // 将base64图片转换为临时地址
  123. base64ToTempFilePath(base64Data, success, fail) {
  124. const fs = uni.getFileSystemManager()
  125. const fileName = 'temp_image_' + Date.now() + '.png' // 自定义文件名,可根据需要修改
  126. const filePath = uni.env.USER_DATA_PATH + '/' + fileName
  127. const buffer = uni.base64ToArrayBuffer(base64Data)
  128. fs.writeFile({
  129. filePath,
  130. data: buffer,
  131. encoding: 'binary',
  132. success() {
  133. success && success(filePath)
  134. },
  135. fail() {
  136. fail && fail()
  137. }
  138. })
  139. },
  140. generatePoster() {
  141. let that = this;
  142. if(this.typeCode=='poster_product'){
  143. if(!this.productTitle||!this.productLink) return req.msg("请先添加产品链接")
  144. }
  145. uni.showLoading({
  146. title: '生成中…',
  147. mask: true
  148. });
  149. this.generate(imgUrl => {
  150. that.imgUrl = imgUrl;
  151. uni.hideLoading();
  152. this.saveImage()
  153. });
  154. },
  155. saveImage() {
  156. let that = this;
  157. utils.saveImage(this.imgUrl);
  158. },
  159. getImageInfo(url) {
  160. return new Promise((resolve, reject) => {
  161. if (!url) {
  162. resolve();
  163. return false;
  164. }
  165. uni.getImageInfo({
  166. src: url,
  167. success: resolve,
  168. fail: reject
  169. });
  170. });
  171. },
  172. generate(success) {
  173. let marginTop = 155;
  174. const avatarPromise = this.getImageInfo(this.posterBg); // 获取小程序码图
  175. let codePromise;
  176. if (!this.code) {
  177. return req.msg('二维码生成失败');
  178. } else {
  179. codePromise = this.getImageInfo(this.code);
  180. } //获取二维码
  181. let that = this;
  182. Promise.all([avatarPromise, codePromise]).then(([avatar, code]) => {
  183. if(avatar.width>670){
  184. this.cwidth = avatar.width
  185. this.cheight = avatar.height+180
  186. }else{
  187. let sc = avatar.width/avatar.height
  188. avatar.width = 670
  189. avatar.height = 670/sc
  190. this.cwidth = avatar.width
  191. this.cheight = avatar.height+180
  192. }
  193. this.showCanvas = false
  194. setTimeout(()=>{
  195. this.showCanvas = true
  196. const ctx = uni.createCanvasContext('share', this); // 绘制背景,填充满整个canvas画布
  197. let width = this.cwidth,
  198. height = this.cheight; //默认背景
  199. // ctx.setFillStyle('red');
  200. // ctx.fillRect(0, 0, width, height); // 画布背景
  201. // ctx.save();
  202. // ctx.beginPath();
  203. that.roundRect(ctx, 0, 0, width, height, 30);
  204. ctx.save();
  205. ctx.drawImage(avatar.path, 0, 0, width, avatar.height)
  206. // ctx.restore();
  207. let nickName = this.userInfo.realName?this.userInfo.realName:(this.userInfo.nickName?this.userInfo.nickName:'');
  208. nickName = nickName+' | 中国人寿股份湖南分公司'
  209. if(this.typeCode=="poster_product") nickName = this.productTitle
  210. ctx.fillStyle = '#333333';
  211. ctx.font = '400 28px PingFang SC';
  212. ctx.fillText(nickName, 35, avatar.height+80);
  213. let s = this.typeCode=="poster_product"?'长按二维码了解更多':'长按小程序码了解更多'
  214. ctx.fillStyle = '#999999';
  215. ctx.font = '26px PingFang SC';
  216. ctx.fillText(s, 35, avatar.height+130);
  217. ctx.drawImage(code.path, width-126-35, avatar.height+30, 126,
  218. 126)
  219. ctx.draw(false, function() {
  220. uni.canvasToTempFilePath({
  221. canvasId: 'share',
  222. success: function(res) {
  223. success.call(this, res.tempFilePath);
  224. },
  225. fail: function(res) {
  226. // console.log(res);
  227. }
  228. },
  229. that
  230. );
  231. });
  232. },500)
  233. });
  234. },
  235. /**
  236. *
  237. * @param {CanvasContext} ctx canvas上下文
  238. * @param {number} x 圆角矩形选区的左上角 x坐标
  239. * @param {number} y 圆角矩形选区的左上角 y坐标
  240. * @param {number} w 圆角矩形选区的宽度
  241. * @param {number} h 圆角矩形选区的高度
  242. * @param {number} r 圆角的半径
  243. */
  244. roundRect: function(ctx, x, y, w, h, r, c) {
  245. // 开始绘制
  246. ctx.beginPath(); // 因为边缘描边存在锯齿,最好指定使用 transparent 填充
  247. // 这里是使用 fill 还是 stroke都可以,二选一即可
  248. ctx.setFillStyle(c ? c : 'white'); // ctx.setStrokeStyle('transparent')
  249. // 左上角
  250. ctx.arc(x + r, y + r, r, Math.PI, Math.PI * 1.5); // border-top
  251. ctx.moveTo(x + r, y);
  252. ctx.lineTo(x + w - r, y);
  253. ctx.lineTo(x + w, y + r); // 右上角
  254. ctx.arc(x + w - r, y + r, r, Math.PI * 1.5, Math.PI * 2); // border-right
  255. ctx.lineTo(x + w, y + h - r);
  256. ctx.lineTo(x + w - r, y + h); // 右下角
  257. ctx.arc(x + w - r, y + h - r, r, 0, Math.PI * 0.5); // border-bottom
  258. ctx.lineTo(x + r, y + h);
  259. ctx.lineTo(x, y + h - r); // 左下角
  260. ctx.arc(x + r, y + h - r, r, Math.PI * 0.5, Math.PI); // border-left
  261. ctx.lineTo(x, y + r);
  262. ctx.lineTo(x + r, y); // 这里是使用 fill 还是 stroke都可以,二选一即可,但是需要与上面对应
  263. ctx.fill(); // ctx.stroke()
  264. ctx.closePath(); // 剪切
  265. ctx.clip();
  266. }
  267. },
  268. mounted() {},
  269. }
  270. </script>
  271. <style>
  272. @import "./posterService.css";
  273. </style>