posterService.vue 9.2 KB

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