shopro-share.vue 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571
  1. <template>
  2. <view class="content">
  3. <!-- 海报弹窗 -->
  4. <view class="cu-modal" :class="{ show: showPoster }" @tap="onClosePoster">
  5. <view class="cu-dialog" style="width: 640rpx;background: none;">
  6. <view class="poster-img-box"><image class="poster-img" :src="posterImage" mode="widthFix"></image></view>
  7. <view class="poster-btn-box u-m-t-20 u-flex u-row-between u-col-center" v-show="posterImage">
  8. <button class="cancel-btn u-reset-button" @tap="showPoster = false">取消</button>
  9. <button class="save-btn u-reset-button" @tap="saveImage">{{ ['wxOfficialAccount', 'H5'].includes(platform) ? '长按图片保存' : '保存图片' }}</button>
  10. </view>
  11. </view>
  12. </view>
  13. <!-- 分享tools -->
  14. <view class="cu-modal bottom-modal" :class="{ show: showShare }" @tap="showShare = false">
  15. <view class="cu-dialog safe-area-inset-bottom" style="border-radius: 20rpx 20rpx 0 0;background: none;">
  16. <view class="share-box">
  17. <view class="share-list-box u-flex">
  18. <!-- #ifdef MP-WEIXIN -->
  19. <button class="share-item share-btn u-flex-col u-col-center" open-type="share">
  20. <image class="share-img" :src="$IMG_URL + '/imgs/share/share_wx.png'" mode=""></image>
  21. <text class="share-title">微信好友</text>
  22. </button>
  23. <!-- #endif -->
  24. <!-- #ifndef MP-WEIXIN -->
  25. <view v-if="platform !== 'H5'" class="share-item u-flex-col u-col-center" @tap="shareFriend">
  26. <image class="share-img" :src="$IMG_URL + '/imgs/share/share_wx.png'" mode=""></image>
  27. <text class="share-title">微信好友</text>
  28. </view>
  29. <!-- #endif -->
  30. <view class="share-item u-flex-col u-col-center" @tap="onPoster">
  31. <image class="share-img" :src="$IMG_URL + '/imgs/share/share_poster.png'" mode=""></image>
  32. <text class="share-title">生成海报</text>
  33. </view>
  34. <view class="share-item u-flex-col u-col-center" @tap="copySharePath">
  35. <image class="share-img" :src="$IMG_URL + '/imgs/share/share_link.png'" mode=""></image>
  36. <text class="share-title">复制链接</text>
  37. </view>
  38. </view>
  39. <view class="share-foot u-flex u-row-center u-col-center" @tap="showShare = false">取消</view>
  40. </view>
  41. </view>
  42. </view>
  43. <!-- 分享指引 -->
  44. <view class="cu-modal bottom-modal" :class="{ show: showShareGuide }" @tap="showShareGuide = false">
  45. <view class="cu-dialog safe-area-inset-bottom" style="border-radius: 20rpx 20rpx 0 0;background: none;vertical-align: top;">
  46. <view class="guide-wrap u-flex u-col-top u-row-center"><image class="guide-img" :src="$IMG_URL + '/imgs/share/share_guide.png'" mode=""></image></view>
  47. </view>
  48. </view>
  49. <!-- 各海报模块 -->
  50. <shopro-canvas v-if="showPoster" ref="shoproCanvas" :canvasParams="canvasParams" @success="onSuccess"></shopro-canvas>
  51. </view>
  52. </template>
  53. <script>
  54. /**
  55. * 分享弹窗
  56. * @property {Boolean} value = showModal - v-model控制显隐
  57. * @property {String} posterType - 海报类别
  58. * @property {Object} posterInfo - 海报数据
  59. */
  60. import { mapMutations, mapActions, mapState, mapGetters } from 'vuex';
  61. import Auth from '@/shopro/permission/index.js';
  62. export default {
  63. name: 'shoproShare',
  64. components: {},
  65. data() {
  66. return {
  67. showShareGuide: false, //H5的指引。
  68. showPoster: false, //海报弹窗
  69. platform: this.$platform.get(),
  70. posterImage: '',
  71. canvasParams: {}
  72. };
  73. },
  74. props: {
  75. posterType: {
  76. type: String,
  77. default: ''
  78. },
  79. posterInfo: {
  80. type: Object,
  81. default: () => {}
  82. },
  83. value: {}
  84. },
  85. computed: {
  86. ...mapGetters(['initShare', 'userInfo', 'isLogin', 'shareInfo']),
  87. showShare: {
  88. get() {
  89. return this.value;
  90. },
  91. set(val) {
  92. if (!this.showPoster) {
  93. val ? uni.hideTabBar() : uni.showTabBar();
  94. }
  95. this.$emit('input', val);
  96. }
  97. }
  98. },
  99. created() {
  100. uni.$on('ON_WX_SHARE', () => {
  101. this.showShare = false;
  102. });
  103. },
  104. methods: {
  105. // 关闭弹窗
  106. onClosePoster() {
  107. this.showPoster = false;
  108. uni.showTabBar();
  109. },
  110. // 绘制成功
  111. onSuccess(e) {
  112. this.posterImage = e;
  113. },
  114. // 开始绘制
  115. onPoster() {
  116. this.posterImage = '';
  117. uni.hideTabBar();
  118. if (this.$store.getters.isLogin) {
  119. this.canvasParams = this.getPosterFormatter();
  120. this.showPoster = true;
  121. } else {
  122. this.$store.dispatch('showAuthModal', 'accountLogin');
  123. }
  124. this.showShare = false;
  125. },
  126. // 分享好友
  127. shareFriend() {
  128. let that = this;
  129. // #ifdef APP-PLUS
  130. uni.share({
  131. provider: 'weixin',
  132. scene: 'WXSceneSession',
  133. type: 0,
  134. href: that.shareInfo.path,
  135. title: that.shareInfo.title,
  136. summary: that.shareInfo.title,
  137. image: that.shareInfo.image,
  138. success: res => {
  139. console.log('success:' + JSON.stringify(res));
  140. this.showShare = false;
  141. },
  142. fail: err => {
  143. console.log('fail:' + JSON.stringify(err));
  144. }
  145. });
  146. // #endif
  147. // #ifdef H5
  148. this.showShare = false;
  149. this.showShareGuide = true;
  150. // #endif
  151. },
  152. // 保存图片
  153. async saveImage() {
  154. let that = this;
  155. if (['wxOfficialAccount', 'H5'].includes(this.platform)) {
  156. this.$u.toast('长按图片保存');
  157. return false;
  158. }
  159. let authState = await new Auth('writePhotosAlbum').check();
  160. if (authState) {
  161. uni.saveImageToPhotosAlbum({
  162. filePath: that.posterImage,
  163. success: res => {
  164. this.$u.toast('保存成功');
  165. this.showPoster = false;
  166. },
  167. fail: err => {
  168. console.log(`图片保存失败:`, err);
  169. this.$u.toast('保存失败');
  170. }
  171. });
  172. }
  173. },
  174. // 复制链接
  175. copySharePath() {
  176. let that = this;
  177. uni.setClipboardData({
  178. data: that.shareInfo.copyLink,
  179. success: data => {
  180. that.$u.toast('已复制到剪切板');
  181. that.showShare = false;
  182. }
  183. });
  184. },
  185. // 获取海报格式,规则说明在@/shopro/poster/tools.js中的initDrawArray
  186. getPosterFormatter() {
  187. const that = this;
  188. let data = {};
  189. switch (this.posterType) {
  190. case 'user':
  191. data = {
  192. backgroundImage: that.initShare.user_poster_bg,
  193. drawArray: [
  194. {
  195. name: '用户昵称',
  196. type: 'text',
  197. text: that.userInfo.nickname,
  198. isBgCenter: true,
  199. size: 28,
  200. dy: 250,
  201. color: '#333',
  202. textAlign: 'middle',
  203. textBaseLine: 'middle'
  204. },
  205. {
  206. name: 'avatar',
  207. type: 'image',
  208. url: that.userInfo.avatar,
  209. alpha: 1,
  210. isBgCenter: true,
  211. dy: 95,
  212. dWidth: 120,
  213. dHeight: 120,
  214. circleSet: {}
  215. },
  216. // #ifdef MP-WEIXIN
  217. {
  218. name: 'wxCode',
  219. type: 'image',
  220. url: `${that.$API_URL}wechat/wxacode?scene=${that.shareInfo.query}`,
  221. alpha: 1,
  222. dy: 560,
  223. isBgCenter: true,
  224. dWidth: 180,
  225. dHeight: 180
  226. },
  227. // #endif
  228. // #ifndef MP-WEIXIN
  229. {
  230. name: '普通二维码',
  231. type: 'qrcode',
  232. text: that.shareInfo.path,
  233. size: 180,
  234. dy: 560,
  235. isBgCenter: true
  236. }
  237. // #endif
  238. ]
  239. };
  240. break;
  241. case 'goods':
  242. data = {
  243. backgroundImage: that.initShare.goods_poster_bg,
  244. drawArray: [
  245. {
  246. name: 'avatar',
  247. type: 'image',
  248. url: that.userInfo.avatar,
  249. alpha: 1,
  250. dy: 40,
  251. dx: 38,
  252. dWidth: 80,
  253. dHeight: 80,
  254. circleSet: {}
  255. },
  256. {
  257. type: 'text',
  258. text: that.userInfo.nickname,
  259. size: 28,
  260. color: '#333',
  261. alpha: 1,
  262. textAlign: 'middle',
  263. textBaseline: 'bottom',
  264. dx: 140,
  265. dy: 40
  266. },
  267. {
  268. type: 'text',
  269. text: '推荐一个好物给你,请查收!',
  270. size: 26,
  271. color: '#333',
  272. alpha: 1,
  273. textAlign: 'middle',
  274. textBaseline: 'middle',
  275. dx: 140,
  276. dy: 80
  277. },
  278. {
  279. name: 'goodsImage',
  280. type: 'image',
  281. url: that.posterInfo.image,
  282. alpha: 1,
  283. isBgCenter: true,
  284. dy: 140,
  285. dWidth: 620,
  286. dHeight: 620,
  287. roundRectSet: {
  288. r: 20
  289. }
  290. },
  291. {
  292. type: 'text', //标题
  293. text: that.posterInfo.title,
  294. size: 28,
  295. color: '#333',
  296. alpha: 1,
  297. textAlign: 'left',
  298. textBaseline: 'middle',
  299. fontWeight: 'bold',
  300. lineFeed: {
  301. maxWidth: 620,
  302. lineHeight: 40,
  303. lineNum: 2
  304. },
  305. dx: 36,
  306. dy: 780
  307. },
  308. {
  309. type: 'text',
  310. text: `¥${that.posterInfo.price}`,
  311. size: 38,
  312. color: '#E1212B',
  313. alpha: 1,
  314. textAlign: 'left',
  315. textBaseline: 'middle',
  316. fontWeight: 'bold',
  317. fontFamily: 'OPPOSANS',
  318. dx: 30,
  319. dy: 860
  320. },
  321. {
  322. type: 'text',
  323. text: `¥${that.posterInfo.original_price}`,
  324. size: 28,
  325. color: '#999999',
  326. alpha: 1,
  327. textAlign: 'left',
  328. textBaseline: 'top',
  329. lineThrough: {
  330. style: '#999999'
  331. },
  332. dx: 400,
  333. dy: 860
  334. },
  335. // #ifdef MP-WEIXIN
  336. {
  337. name: 'wxCode',
  338. type: 'image', //微信小程序码
  339. url: `${that.$API_URL}wechat/wxacode?scene=${that.shareInfo.query}`,
  340. alpha: 1,
  341. dx: 522,
  342. dy: 911,
  343. dWidth: 110,
  344. dHeight: 110
  345. },
  346. // #endif
  347. // #ifndef MP-WEIXIN
  348. {
  349. type: 'qrcode',
  350. text: that.shareInfo.copyLink,
  351. size: 110,
  352. dx: 530,
  353. dy: 930
  354. }
  355. // #endif
  356. ]
  357. };
  358. break;
  359. case 'groupon':
  360. data = {
  361. backgroundImage: that.initShare.groupon_poster_bg,
  362. drawArray: [
  363. {
  364. name: 'avatar',
  365. type: 'image',
  366. url: that.userInfo.avatar,
  367. alpha: 1,
  368. dy: 40,
  369. dx: 38,
  370. dWidth: 80,
  371. dHeight: 80,
  372. circleSet: {}
  373. },
  374. {
  375. type: 'text',
  376. text: that.userInfo.nickname,
  377. size: 28,
  378. color: '#333',
  379. alpha: 1,
  380. textAlign: 'middle',
  381. textBaseline: 'bottom',
  382. dx: 140,
  383. dy: 40
  384. },
  385. {
  386. type: 'text',
  387. text: '发现一个好物,快来和我一起拼吧!',
  388. size: 26,
  389. color: '#333',
  390. alpha: 1,
  391. textAlign: 'middle',
  392. textBaseline: 'middle',
  393. dx: 140,
  394. dy: 80
  395. },
  396. {
  397. name: 'goodsImage',
  398. type: 'image',
  399. url: that.posterInfo.goods.image,
  400. alpha: 1,
  401. isBgCenter: true,
  402. dy: 140,
  403. dWidth: 620,
  404. dHeight: 620,
  405. roundRectSet: {
  406. r: 20
  407. }
  408. },
  409. {
  410. type: 'text', //标题
  411. text: that.posterInfo.goods.title,
  412. size: 28,
  413. color: '#333',
  414. alpha: 1,
  415. textAlign: 'left',
  416. textBaseline: 'middle',
  417. fontWeight: 'bold',
  418. lineFeed: {
  419. maxWidth: 620,
  420. lineHeight: 40,
  421. lineNum: 2
  422. },
  423. dx: 36,
  424. dy: 780
  425. },
  426. {
  427. type: 'text',
  428. text: `拼团价:¥${that.posterInfo.goods.groupon_price}`,
  429. size: 32,
  430. color: '#E1212B',
  431. alpha: 1,
  432. textAlign: 'left',
  433. textBaseline: 'middle',
  434. fontWeight: 'bold',
  435. fontFamily: 'OPPOSANS',
  436. dx: 30,
  437. dy: 860
  438. },
  439. {
  440. type: 'text',
  441. text: `${that.posterInfo.num}人团`,
  442. size: 24,
  443. color: '#fff',
  444. alpha: 1,
  445. textAlign: 'left',
  446. textBaseline: 'top',
  447. dx: 565,
  448. dy: 863
  449. },
  450. // #ifdef MP-WEIXIN
  451. {
  452. name: 'wxCode',
  453. type: 'image', //微信小程序码
  454. url: `${that.$API_URL}wechat/wxacode?scene=${that.shareInfo.query}`,
  455. alpha: 1,
  456. dx: 530,
  457. dy: 930,
  458. dWidth: 110,
  459. dHeight: 110
  460. },
  461. // #endif
  462. // #ifndef MP-WEIXIN
  463. {
  464. type: 'qrcode',
  465. text: that.shareInfo.path,
  466. size: 110,
  467. dx: 530,
  468. dy: 930
  469. }
  470. // #endif
  471. ]
  472. };
  473. break;
  474. default:
  475. console.log('%cerr:没有此类型海报数据', 'color:green;background:yellow');
  476. break;
  477. }
  478. return data;
  479. }
  480. }
  481. };
  482. </script>
  483. <style lang="scss">
  484. // 指引
  485. .guide-wrap {
  486. height: 100%;
  487. .guide-img {
  488. width: 580rpx;
  489. height: 430rpx;
  490. }
  491. }
  492. // 分享海报
  493. .poster-btn-box {
  494. .cancel-btn {
  495. width: 300rpx;
  496. height: 70rpx;
  497. line-height: 70rpx;
  498. background: #ffffff;
  499. border-radius: 35rpx;
  500. font-size: 28rpx;
  501. font-weight: 500;
  502. color: #999999;
  503. }
  504. .save-btn {
  505. width: 300rpx;
  506. height: 70rpx;
  507. line-height: 70rpx;
  508. background: linear-gradient(90deg, #e9b461, #eecc89);
  509. border-radius: 35rpx;
  510. font-size: 28rpx;
  511. font-weight: 500;
  512. color: #ffffff;
  513. }
  514. }
  515. .poster-img-box {
  516. .poster-img {
  517. width: 660rpx;
  518. min-height: 800rpx;
  519. border-radius: 20rpx;
  520. }
  521. }
  522. // 分享tool
  523. .share-box {
  524. background: #fff;
  525. width: 750rpx;
  526. border-radius: 30rpx 30rpx 0 0;
  527. padding-top: 30rpx;
  528. position: relative;
  529. .share-foot {
  530. font-size: 24rpx;
  531. color: #bfbfbf;
  532. height: 80rpx;
  533. border-top: 1rpx solid #eee;
  534. }
  535. .share-list-box {
  536. .share-btn {
  537. background: none;
  538. border: none;
  539. line-height: 1;
  540. padding: 0;
  541. &::after {
  542. border: none;
  543. }
  544. }
  545. .share-item {
  546. flex: 1;
  547. padding-bottom: 20rpx;
  548. .share-img {
  549. width: 70rpx;
  550. height: 70rpx;
  551. background: rgba(246, 246, 254, 1);
  552. border-radius: 50%;
  553. margin-bottom: 20rpx;
  554. }
  555. .share-title {
  556. font-size: 24rpx;
  557. color: #666;
  558. }
  559. }
  560. }
  561. }
  562. </style>