uniapp 实现分享海报功能

2,170 阅读7分钟

需求:小程序内点击分享按钮,将当前页面,已海报形式进行分享,用户可通过海报上的二维码,扫描进入到该界面,实现原理主要是通过lime-painter插件,生产canvas模板,复制即用,废话不多说,直接上代码。

插件地址+教程: ext.dcloud.net.cn/plugin?id=2…

效果图展示:

a76c7e397479e8fe6ab7e615d530e89.jpg

分享海报功能:

<view class="share-item" @click="shareCanvas" style="margin-top: -7rpx;">
   <image src="/static/images/share2.png"></image>
   <text style="margin-top: 8rpx;">分享海报</text>
</view>

// 生成分享海报
shareCanvas() {
    // this.showCanvas = true;
    uni.showLoading({
        mask: true,
        title: '正在生成海报'
    });////
    // #ifdef H5
    let origin = "h5";
    let url = this.$c.shareH5Url + "/subpages/content/buyUserTicket/index?routeId=" + this.postId
    // #endif
    // #ifdef MP-WEIXIN
    let origin = "weixin";
    let customerPushCode = uni.getStorageSync("userInfo").pushCode || ''
    let url = `/subpages/content/buyUserTicket/index?routeId=${this.postId}&pushCode=${customerPushCode}`
    // #endif
    console.log(url, 'urlurlurlurl')
    this.$H.get('/business/app/tripTourRoute/qrWxCode', {
        url: url
     }).then(res => {
        if (res.code == 0) {
            this.configData = {
                posterQrcode: res.result,
                routeName: this.detailContent.routeName,
                posterImg: this.detailContent.miediaList[0].mediaPath
            }
            this.showCanvas = true;
        }
        uni.hideLoading();
    });
},

海报组件:

<!-- 生成海报组件 -->
<poster v-if="showCanvas" ref="posterRef" :configData="configData" @close="closePopup"/>

import poster from "./poster.vue";

poster.vue页面:

<template>
  <view class="main">
    <!-- :mask-close-able="false" 点击遮罩关闭 -->
    <u-popup class="poster-oppup" ref="popupRef" mode="center" width="90%" height="auto" :custom-style="customStyle"
      :safe-area-inset-bottom="true" :closeable="!show" v-model="pop" 
      :close-icon-size="36" close-icon-color="#d53228">
      <view class="content">
        <image v-if="!show" class="poster-img" :src="path" mode="widthFix"></image>
	<view v-else style="display: flex; align-items: center; justify-content: center; height: 1100rpx;">
         <u-loading :show="show" class="loading" size="84" mode="flower"></u-loading>
    </view>
    <!-- width 越小,越放大 -->
    <!-- background-color: #ffffff; 要设置背景位白色,不然保存的图标黑底 -->
        <l-painter ref="painter" isCanvasToTempFilePath @success="path = $event;show = false;"  custom-style="position: fixed; left: 200%" css="width: 670rpx; padding: 20rpx; background-color: #ffffff;">
    <l-painter-view css="border-bottom: 2rpx dashed #817EF7; padding-bottom: 20rpx; display: flex; align-items: center;">
	<l-painter-image :src="userInfo.avatar" css="margin-right: 20rpx; width: 100rpx;  height: 100rpx; border-radius: 50%;"/>
	<l-painter-view css="display: inline-block; ">
	<l-painter-text :text="userInfo.username" css="display: block; padding-bottom: 10rpx; color: #000000; font-size: 30rpx;"/>
        <l-painter-text text="就等你了,赶快来一起出游吧!" css="color: #817EF7; font-size: 28rpx"/>
	</l-painter-view>
	</l-painter-view>
					
         <l-painter-view css="margin-top: 20rpx; box-sizing: border-box; border-radius: 10rpx;">
           <l-painter-image :src="configData.posterImg" css="object-fit: cover; object-position: 50% 50%; width: 630rpx; height: 560rpx; border-radius: 20rpx;"/>
	<l-painter-view css="display: flex; margin-top: 20rpx; border-top: 2rpx dashed #817EF7; padding-top: 30rpx;">
	 <l-painter-view >
<l-painter-text v-if="configData.routeName.length > 16" :text="configData.routeName" css="line-clamp: 2; display: block; font-size: 30rpx; color: #333333; width: 440rpx; font-weight: bold; margin-bottom: 44rpx" />
	<l-painter-text v-else :text="configData.routeName" css="line-clamp: 2; display: block; font-size: 30rpx; color: #333333; width: 440rpx; font-weight: bold; margin-bottom: 90rpx" />
<l-painter-text text="微信扫码获得更多详情" css="font-size: 28rpx; color: #817EF7; display: block;"/>
	</l-painter-view>
	<l-painter-image :src="configData.posterQrcode" css="width: 168rpx; height: 168rpx; object-fit: cover;"/>
	</l-painter-view>
          </l-painter-view>
        </l-painter>
      </view>
	<view v-if="!show" class="save-btn" @tap="saveImg">
	<text>保存分享</text>
	</view>
    </u-popup>
    </view>
  </view>
</template>
<script>
export default {
  name: "adv",
  props: {
    configData: Object,
  },
  data() {
    return {
			userInfo: uni.getStorageSync("userInfo"),
      customStyle: {
        backgroundColor: "transparent",
        height: "90vh",
        marginTop:"20rpx",
      },
      path: "",
      pop: true,
      show: true
    };
  },
  watch: {
    pop: {
      handler(newval, oldVal) {
        if (!newval) {
          this.$emit("close");
        }
      }
    },
  },
  methods: {
    // 保存海报到相册
    saveImg() {
            let filePathData = ''
            // #ifdef MP-WEIXIN
            // 生成图片
            this.$refs.painter.canvasToTempFilePathSync({
              fileType: "jpg",
              // 如果返回的是base64是无法使用 saveImageToPhotosAlbum,需要设置 pathType为url
              pathType: 'url',
              quality: 1,
              success: (res) => {
                console.log(res.tempFilePath);
                            filePathData = res.tempFilePath
                // 非H5 保存到相册
                uni.saveImageToPhotosAlbum({
                    filePath: res.tempFilePath,
                    success: function () {
                      uni.showToast({
                            title: '图片保存成功'
                      });
                    },
                    fail: function(error) {
                      uni.showModal({
                        title: '图片保存失败',
                        content: '请确认是否已开启授权',
                        confirmText: '开启授权',
                        success(res) {
                                if (res.confirm) {
                                    uni.openSetting({
                                      success(settingdata) {
                                        if (settingdata.authSetting[
                                            "scope.writePhotosAlbum"
                                           ])
                                          {
                                           uni.showToast({									title: '授权成功,请重试哦~',
                                           icon: "none"
                                          });
													} else {                                                                                         uni.showToast({
                    title: '请确定已打开保存权限',								icon: "none"										});
													}
												}
})
}
}
})
},
	});
			  },
			});
			// #endif
			// #ifdef H5
			var oA = document.createElement('a');
			oA.download = ''; // 设置下载的文件名,默认是’下载’
			oA.href = filePathData;
			document.body.appendChild(oA);
			oA.click();
			oA.remove(); // 下载之后把创建的元素删除
			// #endif
			
			return
			// #ifdef MP-WEIXIN
			// errMsg: "saveImageToPhotosAlbum: fail api scope is not declared in the privacy agreement"
			uni.getImageInfo({
				src: this.posterUrl,
				success: function(image) {
					uni.saveImageToPhotosAlbum({
						filePath: image.path,
						success: function(sucess) {
							uni.showToast({
								title: '图片保存成功'
							});
						},
						
					});
				},
				fail() {}
			});
			// #endif
			// #ifdef H5
			var oA = document.createElement('a');
			oA.download = ''; // 设置下载的文件名,默认是’下载’
			oA.href = this.posterUrl;
			document.body.appendChild(oA);
			oA.click();
			oA.remove(); // 下载之后把创建的元素删除
			// #endif
		},
  },
};
</script>
<style lang="scss" scoped>
    .main {
        .poster-oppup {
            .u-mode-center-box {
               border-radius: 20rpx;
            }
            .poster-img {
                width: 900rpx;
                border-radius: 20rpx;
        }
    }
    .save-btn {
        width: 100%; 
        display: flex;
        justify-content: center;
        text {
            width: 408rpx;
            height: 70rpx;
            margin-bottom: 40rpx;
            font-size: 30rpx; color: #FFFFFF;
            background: linear-gradient( 180deg, #CECDFF 0%, #817EF7 100%);
            border-radius: 35rpx 35rpx 35rpx 35rpx;
            text-align: center; line-height: 70rpx;
        }
    }
 }

</style>

完整代码:index.vue

<template>
	<view class="full-container">
		 <u-navbar></u-navbar>
		<view class="swiper-box hight-swiper-box">
			<u-swiper @click="onSwiper" :list="detailContent.miediaList" name="mediaPath" border-radius="0" mode="rect" indicator-pos="bottomRight" img-mode="aspectFill"></u-swiper>
		</view>
		<view class="main-box">
			<view class="scienc-info">
				<view class="desc ellipsis">{{ detailContent.routeName }}</view>
				<view class="tip two-ellipsis">{{ detailContent.description }}</view>
				<view class="extension-vontainer" @click="getExtension">
					<view class="flex">
						<image class="notice-icon" :src="$IMG + '/images/notice-icon.png'"></image>
						<view class="common-tip puoduct">推广计划产品</view>
						<view class="common-tip plan">本产品已参与推广计划</view>
						</view>
					<image class="two-right-icon" :src="$IMG + '/images/two-right-icon.png'"></image>
				</view>
				<view class="price-box">
					<view class="money">	
						<view class="hot-flex">
							<view class="symbol"></view>
							<view class="money">{{ detailContent.price }}</view>
							<view class="text">起/人</view>
						</view>
					</view>
					<view class="person" v-if="detailContent.joinNumber > 0">{{ detailContent.joinNumber }}人参加</view>
				</view>  
				<view class="operate-box">
					<view class="flex">
						<view class="flex">
							<image class="icon-img" src="/static/images/adress-icon.png"></image>
							<view class="text">{{ detailContent.destination }}</view>
						</view>
						<view class="flex">
							<image class="icon-img" src="/static/images/time-icon.png"></image>
							<view class="text">{{ detailContent.days }}天</view>
						</view>
						<view class="flex">
							<image class="icon-img" src="/static/images/person-icon.png"></image>
							<view class="text">{{ detailContent.groupNumber }} 人</view>
						</view>
					</view>
					<view class="flex" @click="getShowShare">
						<image class="icon-img share-icon" src="/static/images/share.png"></image>
						<view class="text">分享</view>
					</view>
				</view>
			</view>
	<!-- 		<view class="package-info common-box">
				<view class="nav-tit">
					<text class="tit">套餐信息</text>
					<text class="desc">(进入拼团后再选择)</text>
				</view>
				<view class="flex-container">
					<view class="package-list" v-for="(item, index) in detailContent.packageList" :key="index">
						<text class="name" v-if="!item.tip">{{ item.name }}:¥{{ item.price }}</text>
						<text class="name" v-else>{{ item.name }}({{ item.tip }}):¥{{ item.price }}</text>
					</view>
				</view>
			</view> -->
			<view class="set-out-time common-box">
				<view class="nav-tit">出发日期</view>
				<ticketInfo v-if="showStatus" :dateVoList="dateVoList" :classSyle="classSyle" :pageType="pageType" @getSelectPackage="getSelectPackage"></ticketInfo>
				
			</view>
			<view class="aggregate-info common-box">
				<view class="nav-tit">集合信息</view>
				<view class="list-item" v-for="(item, index) in detailContent.rendezvousList" :key="index">
					</block>
					<view class="default-icon">
						<image class="icon-img" src="/static/images/default-icon.png"></image>
						<text class="icon-index">{{ index + 1}}</text>
					</view>
					<text class="text-desc">{{ item }}</text>
				</view>
			</view>
			<view v-if="detailContent.joinNumber > 0" class="person-info common-box">
				<view class="nav-tit flex" @click="getMorePerson">
					<view class="left">已参加的人</view>
					<view class="flex">
						<view class="number">{{ detailContent.joinNumber }}</view>
						<view class="person"></view>
						<image class="more-arr-img" src="/static/images/more-right.png"></image>
					</view>
				</view>
				<view class="recommend-scroll">
					<scroll-view class="wrap-scroller" scroll-x="true">
						<view class="list-item" v-for="(item, index) in detailContent.personVos" :key="index">
							<image class="avatar-z" :src="item.avatar" mode="aspectFill"></image>
							<view class="name"> {{ item.customerName }} </view>
						</view>
					</scroll-view>
				</view>
			</view>
			
			<view class="bottom-operate">
				<view class="flex">
					<view class="ico-box home-icon" @click.stop="getHome">
						<image class="icon-img" src="/static/images/detail-home.png"></image>
						<view class="text">首页</view>
					</view>
					<view class="ico-box">
						<button open-type="contact" hover-class='none' class='item tui-skeleton-rect' >
							<image class="icon-img" src="/static/images/customer-service.png"></image>
						</button>
						<view class="text">客服</view>
					</view>
				</view>
				<view class="btn-customer-bg" @click="getJoinGroup">加入该团</view>
			</view>
			<lf-popup v-model="showPersonPopup" class="customer-popup">
				<div class="titile-box" @click="onClose">
					<view></view>
					<view class="popup-tit">人员名单</view>
					<image src="/static/images/login-close.png"></image>
				</div>
				<view class="sign-up">已报名</view>
				<view class="list-box">
					<view class="list-item" v-for="(item, index) in detailContent.personVos" :key="index">
						<image class="avatar-z" :src="item.avatar" mode="aspectFill"></image>
						<view class="name"> {{ item.customerName }} </view>
					</view>
				</view>
				
				<view class="bottom">只显示部分报名用户信息</view>
			</lf-popup>
			<!-- 分享选择弹窗 -->
			<lf-popup v-model="showShare" height="240rpx">
				<view class="share-wrap" @click="closeShare">
					<!-- #ifdef MP-WEIXIN -->
					<button open-type="share" class="share-item u-reset-button">
						<image style="width: 86rpx; height: 86rpx; margin-top: 1rpx;" src="/static/wechat.png"></image>
						<text>微信好友</text>
					</button>
					<!-- #endif -->
					<!-- #ifdef H5 -->
					<view class="share-item2" @click="copyPageUrl">
						<image src="/static/images/share.png"></image>
						<text>分享链接</text>
					</view>
					<!-- #endif -->
					<!-- #ifdef H5 || MP-WEIXIN -->
					<view class="share-item" @click="shareCanvas" style="margin-top: -7rpx;">
						<image src="/static/images/share2.png"></image>
						<text style="margin-top: 8rpx;">分享海报</text>
					</view>
					<!-- #endif -->
				</view>
			</lf-popup>
			<toast v-if="loadingFlag" color="#fff" type="rotate3"></toast>
		</view>
		
		<view class="tab-content">
			<Anchor
			:tabList="tabs"
			:barFixed="true"
			:transitionShow="true"
			barHeight="50"
			:barTop="barTop"
			barId="0"
			@clickTabs="clickTabs"
			ref="barTabNav"
			>
				<!-- id与数据tabs->navTarget对应 -->
				<view id="item1">
					<view class="box">
						<mp-html :content="detailContent.routeExtendList[0].details" selectable="true" />
					</view>
					
				</view>
				<view id="item2">
					<view class="box">
						<mp-html :content="detailContent.routeExtendList[1].details" selectable="true" />
					</view>
				</view>
				<view id="item3">
					<view class="box">
						<mp-html :content="detailContent.routeExtendList[2].details" selectable="true" />
					</view>
				</view>
				<view id="item4">
					<view class="box">
						<mp-html :content="detailContent.routeExtendList[3].details" selectable="true" />
					</view>
					<!-- 热门推荐-->
					<group-buying ref="groupBuying" :pageType="pageType" :tittle="groupTittle" :classStyle="classStyle"></group-buying>
				</view>
			</Anchor>
		</view>
		<lf-back-top :show-tag="showTag"></lf-back-top>
		<!-- 生成海报组件 -->
		<poster v-if="showCanvas" ref="posterRef" :configData="configData" @close="closePopup"/>
		<phone-login ref="phoneLogin"></phone-login>
		<extension-popup ref="extensionPopup" @getShare="getShare"></extension-popup>
	</view>
</template>

<script>
import poster from "./poster.vue";
import Anchor from './anchor.vue'
import extensionPopup from './components/extension-popup.vue'
import ticketInfo from '@/subpages/content/components/ticketInfo/index.vue'
export default {
	components:{ 
		poster,
		Anchor,
		ticketInfo,
		extensionPopup
	},
	data() {
		return {
			tabs: [
				{
					text: "详情亮点",//名称
					navTarget: "#item1",//锚点
					value: 'one'
				},
				{
					text: "行程准备",
					navTarget: "#item2",
					value: 'two'
				},
				{
					text: "费用须知",
					navTarget: "#item3",
					value: 'three'
				},
				{
					text: "注意事项",
					navTarget: "#item4",
					value: 'four'
				}
			],
			$IMG: this.$IMG,
			configData: {},
			posterUrl: '',
			showTag: false,
			current: 'one',
			show: false,
			show: true,
			tabCount: '',
			dateVoList: [],
			goTimeOpenId: '',
			showShare: false,
			barTop: 0,
			postId: 0,
			page: 1,
			form: {
				pid: 0,
				type: 1,
				toUid: '',
				toCid: 0,
				postId: '',
				content: ''
			},
			showCanvas: false,
			showStatus: false,
			classSyle: 'buy-ticket',
			postDetail: {},
			commentList: [],
			groupTittle: '热门推荐',
			postingUser: {},
			pageType: 'buyTicket',
			loadingFlag: true,
			detailContent: {
				days: 0,
				price: 0,
				groupNumber: 0,
				routeName: '',
				joinNumber: 0,
				description: '',
				destination: ''
			},
			classStyle: 'buy-ticket',
			tabList: [
				{	name: '详情亮点'	, id: '0' }, 
				{	name: '行程准备'	, id: '1' }, 
				{	name: '费用须知'	, id: '2' }, 
				{	name: '注意事项'	, id: '3' }
			],
			clickFlag: false,
			myScroll: 0,
			currentItem: 0,
			currentTabs: 0,
			showPersonPopup: false,
			shareCover: '',
		}
	},
	
	onShareAppMessage(res) {
		let imgURL = this.shareCover;
		if (this.detailContent.miediaList.length > 0) {
			imgURL = this.detailContent.miediaList[0].mediaPath
		}
		let customerPushCode = uni.getStorageSync("userInfo").pushCode || ''
		return {
			title: this.detailContent.routeName ? this.detailContent.routeName : this.$c.miniappName,
			path: `/subpages/content/buyUserTicket/index?routeId=${this.postId}&pushCode=${customerPushCode}`,
			imageUrl: imgURL
		};
	},
	onShareTimeline(res) {
		let imgURL = this.shareCover;
		if (this.detailContent.miediaList.length > 0) {
			imgURL = this.detailContent.miediaList[0].mediaPath
		}
		let customerPushCode = uni.getStorageSync("userInfo").pushCode || ''
		return {
			title: this.detailContent.routeName ? this.detailContent.routeName : this.$c.miniappName,
			query: `routeId=${this.postId}&pushCode=${customerPushCode}`,
			imageUrl: imgURL
		};
	},
	onShow() {
		uni.removeStorageSync('getDetailFlag')
	},
	onLoad(options) {
		if ('q' in options) {
		const q = decodeURIComponent(options.q);
			const querys = q
			.split('?')[1]
			.split('&')
			.reduce((acc, it) => {
				let r = it.split(/=/);
				return Object.assign(acc, {
				[r[0]]: r[1]
				})
			}, {});
			if ('routeId' in querys) {
				this.postId = querys.routeId.trim();
			}
		}else{
			this.postId = options.routeId.trim();
		}
		this.form.postId = this.postId;
		this.loadingFlag = true
		this.$loading(true)
		this.getInit()
		this.getSysInfo();
		// this.getCommentList()
		uni.setStorageSync('clickTabFlag', false)
		uni.setStorageSync('scrollBtttom', false)
		uni.setStorageSync('clickTabIndex', '0')
		uni.getSystemInfo({
			success: (res) => {
				this.barTop = (res.statusBarHeight) + (res.system.indexOf('iOS') > -1 ? 44 : 48)
			}
		})
	
		this.postingUser = uni.getStorageSync('userInfo')
		//#ifdef MP-WEIXIN
		wx.showShareMenu({
			withShareTicket: true,
			menus: ['shareAppMessage', 'shareTimeline']
		});
		//#endif
	},
	// 1. 点击并且滚动页面,采用点击切换Tab
	onPageScroll(e) {
		this.showTag = e.scrollTop > 750
		uni.setStorageSync('scrollPageFlag', true)
	  this.$refs.barTabNav.getSelectedTab(e.scrollTop, 'scrollPage');
	},
	onReachBottom() {
		uni.setStorageSync('scrollBtttom', true)
		this.$refs.groupBuying.getReachBottom()
		this.$refs.barTabNav.getSelectedTab();
	},
	onPullDownRefresh() {
		setTimeout(() => {
			uni.stopPullDownRefresh();
		}, 500)
	},
	methods: {
		getSysInfo() {
				this.$H.get('system/basic').then(res => {
					this.shareCover = res.shareImg;
				});
			},
		// 获取二维码路径参数
			GetWxMiniProgramUrlParam(url) {
				let theRequest = {};
				if (url.indexOf("#") != -1) {
					const str = url.split("#")[1];
					const strs = str.split("&");
					for (let i = 0; i < strs.length; i++) {
						theRequest[strs[i].split("=")[0]] = decodeURI(strs[i].split("=")[1]);
					}
				} else if (url.indexOf("?") != -1) {
					const str = url.split("?")[1];
					const strs = str.split("&");
					for (let i = 0; i < strs.length; i++) {
						theRequest[strs[i].split("=")[0]] = decodeURI(strs[i].split("=")[1]);
					}
				}
				return theRequest;
			},
		onSwiper(index) {
			let arr = []
			this.detailContent.miediaList.forEach((item) => {
				arr.push(item.mediaPath)
			})
			let currnetImg = this.detailContent.miediaList[index].mediaPath
			uni.previewImage({
				 urls: arr, //预览图片列表
			  current: currnetImg //图片路径
			})
		},
		clickTabs(row, status) {
			// 点击Tab标识
			this.clickFlag = status
			// 避免重复点击
			if(this.current == row.value) return false;
			// 操作处理
			this.current = row.value
		},
		itemChange(id) {
				this.currentItem = id;
			},
			getInit() {
				this.$H.get('/business/app/tripTourRoute/info/' + this.postId).then(res => {
					if (res.code  == 0) {
						this.detailContent = res.result
						if(res.result.personVos !== null) {
							if (res.result.personVos.length > 0) {
								res.result.personVos.forEach((item) => {
									item.customerName = item.nickname.slice(0, 1) + '**'
								})
							}
						}
						this.dateVoList = res.result.goDateVoList
						this.tabCount = this.detailContent.routeExtendList[0].details
						this.showStatus = true
						this.loadingFlag = false
					}
				})
			},
			tabChange(index) {
				this.currentTabs = index;
				this.tabCount = this.detailContent.routeExtendList[index].details
			},
			getMorePerson() {
				this.showPersonPopup = true
			},
			onClose() {
				this.showPersonPopup = false
			},
			getHome() {
				uni.reLaunch({
					url: '/pages/index/index'
				})
			},
			getSelectPackage(data) {
				this.goTimeOpenId = data.openId
				// 清除出行人信息
				uni.setStorageSync('travelersAddFlag', false)
				uni.setStorageSync('finallTravelersUserIds', [])
				uni.setStorageSync('defaultArrData', [])
				uni.setStorageSync('OriginExistenceIds', [])
			},
			getJoinGroup() {
				if (!uni.getStorageSync('hasLogin')) {
					setTimeout(() => {
						uni.showModal({
						  title: '提示',
						  content: '您还未登录,登录体验更多精彩',
						  confirmText: '去登录',
						  cancelText: '随便逛逛',
						  success: (res) => {
						    if (res.confirm) {
						      this.$refs.phoneLogin.getShow()
						    } else if (res.cancel) {
						      console.log('用户点击取消');
						    }
						  }
						});
					}, 500)
				} else {
					if (this.goTimeOpenId) {
						uni.setStorageSync('currentOpenId', this.goTimeOpenId)
						uni.setStorageSync('resortArr', this.detailContent.rendezvousList)
						uni.navigateTo({
							url: `/subpages/content/joinGroup/index?openId=${this.goTimeOpenId}`
						})
					} else {
						this.$u.toast('请选择出发日期');
					}
				}
			},
			getShare() {
				this.showShare = true
			},
			getShowShare() {
				if (!uni.getStorageSync('hasLogin')) {
					setTimeout(() => {
						uni.showModal({
						  title: '提示',
						  content: '您还未登录,登录体验更多精彩',
						  confirmText: '去登录',
						  cancelText: '随便逛逛',
						  success: (res) => {
						    if (res.confirm) {
						      this.$refs.phoneLogin.getShow()
						    } else if (res.cancel) {
						      console.log('用户点击取消');
						    }
						  }
						});
					}, 500)
				} else {
					this.showShare = true
				}
			},
		closeShare() {
			this.showShare = false
		},
			getReplyMore(index) {
				this.commentList[index].copyChildren = this.commentList[index].children
				this.commentList[index].openReplyStatus = false
			},
			// 回复评论
			onReply(e) {
				this.placeholder = '回复:' + e.userInfo.username;
				this.focus = true;
				// toCid: 如果是一级评论传0,如果是针对某一条评论进行回复,传当前评论的id
				this.form.toCid = e.id ? e.id : 0
				// pid: 如果是针对帖子评论传0,如果是针对某一条评论进行回复,传当前评论的id
				this.form.pid = e.pid ? e.pid : e.id
				this.form.toUid = e.userInfo.uid;
				this.form.postId = this.postId;
				this.focusFlag = true
			},
			jumpUser(uid) {
				uni.navigateTo({
					url: '/subpages/childrenPackge/user/home?uid=' + uid
				});
			},
			getCommentList() {
				this.$H.get('comment/list', {
					postId: '1814259461133684738',
					page: this.page
				}).then(res => {
					if (res.code ==0) {
						res.result.data.forEach((item) => {
							if (item.children.length > 1) {
								// item.openReplyStatus = true
								// item.copyChildren = item.children.slice(0, 1)
							} else {
								// item.openReplyStatus = false
								// item.copyChildren = item.children
							}
						})
						this.commentList = this.commentList.concat(res.result.data);
					}
				})
			},
			getExtension() {
				if (!uni.getStorageSync('hasLogin')) {
					setTimeout(() => {
						uni.showModal({
						  title: '提示',
						  content: '您还未登录,登录体验更多精彩',
						  confirmText: '去登录',
						  cancelText: '随便逛逛',
						  success: (res) => {
						    if (res.confirm) {
						      this.$refs.phoneLogin.getShow()
						    } else if (res.cancel) {
						      console.log('用户点击取消');
						    }
						  }
						});
					}, 500)
				} else {
					// 1是推广人
					const userInfo = uni.getStorageSync('userInfo');
					if (userInfo.isPromoter) {
					    if (userInfo.isPromoter === 0) {
					      uni.navigateTo({
					      	url: '/subpages/content/promotion/illustrate'
					      })
					    } else {
					      this.$refs.extensionPopup.getShow(this.postId);
					    }
					} else {
					  uni.navigateTo({
					  	url: '/subpages/content/promotion/illustrate'
					  })
					}
				}
			},
			handleInput() {
				if (this.form.content == '') {
					this.$u.toast('评论不能为空');
					return;
				}
				if (val.detail.cursor == 50) {
					this.$u.toast('内容字数最多为50个字符');
					return;
				}
				uni.showLoading({
					mask: true,
					title: '发布中'
				});
				this.$H.post('post/addComment', this.form).then(res => {
					uni.hideLoading();
					if (res.code == 0) {
						if(res.check){
							uni.showModal({
								title: '提示',
								content: '评论审核通过后发布哦,请耐心等待',
								showCancel: false,
								success: function (res) {
									if (res.confirm) {
									}
								}
							});
						}else{
							this.$u.toast('评论成功');
							this.postDetail.commentCount+=1
						}
						this.form.content = '';
						this.page = 1;
						this.commentList = [];
						this.form.pid = 0;
						// this.getCommentList();
					}else if(res.code==500){
						this.$u.toast(res.msg);
					}
				});
			},
			// 长按 删除评论
			delComment(e, index, index2) {
				let that = this;
				let user = uni.getStorageSync('userInfo');
				//如果是子评论需要遍历子评论查询是否存在自己回复的评论消息
				var flag = false; //这个用来确定父评论下是否存在用户自己的子评论
				var i = 0; //这个用来锁定子评论楼层位置
				e.children.map((item) => {
					if (item.uid == user.uid) {
						flag = true;
						e.id = item.id;
						if (index2) {
							index2 = i;
						}
					}
					i++;
				});
			
				if (e.uid != user.uid) {
					if (!flag) {
						return;
					}
				}
				uni.showModal({
					title: '提示',
					content: '确定删除自己的评论嘛?',
					success: function(res) {
						if (res.confirm) {
							that.$H
								.post('comment/del', {
									id: e.id
								})
								.then(res2 => {
									if (res2.code == 0) {
										// if (index2 || index2 === 0) {
										// 	that.commentList[index].children.splice(index2, 1);
										// } else {
										// 	that.commentList.splice(index, 1);
										// }
										that.postDetail.commentCount --
										// that.getCommentList('delete');
									}
								});
						}
					}
				});
			},
		
			// 生成分享海报
			shareCanvas() {
				// this.showCanvas = true;
				uni.showLoading({
					mask: true,
					title: '正在生成海报'
				});////
				// #ifdef H5
				let origin = "h5";
				let url = this.$c.shareH5Url + "/subpages/content/buyUserTicket/index?routeId=" + this.postId
				// #endif
				// #ifdef MP-WEIXIN
				let origin = "weixin";
				let customerPushCode = uni.getStorageSync("userInfo").pushCode || ''
				let url = `/subpages/content/buyUserTicket/index?routeId=${this.postId}&pushCode=${customerPushCode}`
				// #endif
				console.log(url, 'urlurlurlurl')
				this.$H.get('/business/app/tripTourRoute/qrWxCode', {
						// routeId: this.postId,
						// pushCode: customerPushCode,
						url: url
					})
					.then(res => {
						if (res.code == 0) {
							this.configData = {
								posterQrcode: res.result,
								routeName: this.detailContent.routeName,
								posterImg: this.detailContent.miediaList[0].mediaPath
							}
							this.showCanvas = true;
						}
						uni.hideLoading();
					});
			},
			// 保存海报到相册
			saveImg() {
				// #ifdef MP-WEIXIN
				// errMsg: "saveImageToPhotosAlbum: fail api scope is not declared in the privacy agreement"
				uni.getImageInfo({
					src: this.posterUrl,
					success: function(image) {
						uni.saveImageToPhotosAlbum({
							filePath: image.path,
							success: function(sucess) {
								uni.showToast({
									title: '图片保存成功'
								});
							},
							fail: function(error) {
								uni.showModal({
									title: '图片保存失败',
									content: '请确认是否已开启授权',
									confirmText: '开启授权',
									success(res) {
										if (res.confirm) {
											uni.openSetting({
												success(settingdata) {
													if (settingdata.authSetting[
															"scope.writePhotosAlbum"
														]) {
														uni.showToast({
															title: '授权成功,请重试哦~',
															icon: "none"
														});
													} else {
														uni.showToast({
															title: '请确定已打开保存权限',
															icon: "none"
														});
													}
												}
											})
										}
									}
								})
							},
						});
					},
					fail() {}
				});
				// #endif
				// #ifdef H5
				var oA = document.createElement('a');
				oA.download = ''; // 设置下载的文件名,默认是’下载’
				oA.href = this.posterUrl;
				document.body.appendChild(oA);
				oA.click();
				oA.remove(); // 下载之后把创建的元素删除
				// #endif
			},
			// 销毁组件
			closePopup() {
			  this.showCanvas = false;
			},
	}
}
</script>

<style scoped lang="scss">
	.tab-content {
		padding-bottom: 125rpx;
	}

/* 占位内容 */
.seize {
	padding: 40px;
	text-align: center;
}
/* END */


/* 选项卡样式 */
.tabs {
	background: #fff;
	width: 100%;
}
/* END */

.box {
	padding: 20px;
	background-color: #fff;
	border-bottom: 20rpx solid #F6F7F9;
}



.btn-customer-bg {
		width: 408rpx;
	}
	.full-container {
		background-color: #F6F7F9;
		.common-box {
			background: #fff;
			margin: 10rpx 0;
			padding: 0 40rpx 20rpx 40rpx;
		}
		.flex {
			display: flex;
			align-items: center;
		}
		.list-item {
			text-align: center;
			display: inline-block;
			margin-right: 80rpx;
			.avatar-z {
				width: 70rpx;
				height: 70rpx;
				border-radius: 50%;
			}
			.name {
				color: #000000;
				margin-top: -6rpx;
				font-size: 24rpx;
			}
		}
		.list-item:nth-child(5n) {
			margin-right: 0;
		}
		.banner-img {
			width: 750rpx;
			height: 560rpx;
			display: block;
		}
		.main-box {
			// padding-bottom: 149rpx;
			.scienc-info {
				padding: 0 40rpx;
				background: #fff;
				.desc {
					font-weight: 600;
					color: #333333;
					font-size: 30rpx;
					padding: 20rpx 0 10rpx 0;
				}
				.tip {
					color: #333333;
					font-size: 28rpx;
					margin-bottom: 20rpx;
				}
				.price-box {
					display: flex;
					align-items: center;
					justify-content: space-between;
					.person {
						color: #666666;
						font-size: 24rpx;
					}
				}
				.extension-vontainer {
					display: flex;
					width: 670rpx;
					height: 46rpx;
					background: #E4E3FF;
					align-items: center;
					margin-bottom: 20rpx;
					border-radius: 23rpx;
					padding: 0 20rpx 0 10rpx;
					justify-content: space-between;
					.notice-icon {
						width: 34rpx;
						height: 34rpx;
						margin-right: 10rpx;
					}
					.common-tip {
						color: #817EF7;
						font-size: 24rpx;
					}
					.puoduct {
						padding-top: 9rpx;
					}
					.plan {
						padding-top: 8rpx;
					}
					.puoduct::after {
						content: '';
						height: 38rpx;
						width: 2rpx;
						display: inline-block;
						background-color: #817EF7;
						vertical-align: middle;
						margin: 0 10rpx 8rpx 10rpx;
					}
					.two-right-icon {
						width: 20rpx;
						height: 20rpx;
					}
				}
				.operate-box {
					padding: 30rpx 0 20rpx 0;
					.flex {
						display: flex;
						align-items: center;
						margin-right: 20rpx;
					}
					display: flex;
					justify-content: space-between;
					.icon-img {
						width: 40rpx;
						height: 40rpx;
					}
					.text {
						color: #666666;
						font-size: 24rpx;
						margin-left: 8rpx;
					}
				}
			}
			.package-info {
				.nav-tit {
					display: flex;
					align-items: center;
					padding: 20rpx 0 0 0;
					.tit {
						font-size: 30rpx;
						font-weight: 600;
					}
					.desc {
						font-size: 24rpx;
						margin-top: 5rpx;
					}
				}
				.flex-container {
					display: flex;
					flex-wrap: wrap;
					.package-list {
						margin-bottom: 10rpx;
						.name {
							font-size: 26rpx;
							color: #000000;
							padding: 10rpx 16rpx;
							background: #F6F7F9;
							margin: 0 20rpx 10rpx 0;
							border-radius: 4rpx 4rpx 4rpx 4rpx;
						}
						.name:last-child {
							margin: 0 20rpx 0 0;
						}
						.desc {
							color: #333333;
							font-size: 24rpx;
							margin: 5prx 0 0 10rpx;
						}
					}
				}
			}
			// .share-icon{
			// 	animation: name 0.75s ease infinite;
			// }
			// @keyframes name{
			// 	0% {transform: scale(1);}
			// 	50% {transform: scale(1.35);}
			// 	100% {transform: scale(1)}
			// }


			.set-out-time {
				padding: 0 40rpx 20rpx 40rpx;
				.nav-tit {
					// padding: 20rpx 0 20rpx 40rpx;
				}
				
			}
			.aggregate-info {
				.list-item {
					display: flex;
					align-items: center;
					margin-bottom: 26rpx;
					.text-desc {
						font-size: 28rpx;
					}
					.icon-img {
						width: 42rpx;
						height: 42rpx;
						margin-right: 12rpx;
					}
					.name {
						color: #333333;
						font-size: 24rpx;
					}
					.default-icon {
						display: flex;
						position: relative;
						.icon-index {
							top: 50%;
							left: 40%;
							color: #FFFFFF;
							font-size: 20rpx;
							transform: translate(-50%, -50%);
							position: absolute;
							
						}
					}
				}
				.list-item:last-child {
					margin-bottom: 0;
				}
			}
			.person-info {
				.nav-tit {
					justify-content: space-between;
					.number {
						color: #817EF7;
						font-size: 24rpx;
					}
					.person {
						font-size: 24rpx;
						color: #333333;
						margin-right: 8rpx;
					}
				}
			}
			.tab-info {
				.tab-content {
					padding-top: 15rpx;
					padding-left: 40rpx;
					background-color: #fff;
					.tabs-item {
						margin-right: 60rpx;
						.flex {
							margin-left: 28rpx;
							.line-bottom {
								width: 50rpx;
							}
						}
					}
				}
				.conent {
					color: #666666;
					font-size: 28rpx;
					padding: 40rpx;
					background: #fff;
				}
			}
			.comment-box {
				padding-bottom: 180rpx;
				.avatar {
					width: 80rpx;
					height: 80rpx;
					border-radius: 50%;
					margin-right: 10rpx;
				}
				.comment-tool {
					display: flex;
					align-items: center;
					margin-bottom: 40rpx;
					.send-input {
						height: 36rpx;
						color: #666666;
						font-size: 26rpx;						
						background-color: #F6F6F6;
						padding: 27rpx 30rpx 16rpx 30rpx;
						border-radius: 34rpx 34rpx 34rpx 34rpx;
					}
				}
				.comment-item {
					.flex {
						.user {
							.user-name {
								color: #333333;
								font-size: 28rpx;
								font-weight: 600;
								margin-right: 10rpx;
							}
							.user-time {
								color: #666666;
								font-size: 26rpx;
							}
						}
					}
					.reply-desc {
						color: #666666;
						font-size: 26rpx;
						margin-left: 90rpx;
					}
				}
				.reply-comment-list {
					background: #F6F7F9;
					margin: 20rpx 0 0 90rpx;
					padding: 20rpx 30rpx;
					border-radius: 10rpx 10rpx 10rpx 10rpx;
					.sub-comment-item {
						margin-bottom: 10rpx;
						.flex {
							color: #333333;
							font-size: 24rpx;
							.name {
								color: #817EF7;
							}
							.content {
								word-break: break-all;
							}
						}
						.open-more {
							color: #6F97CB;
							font-size: 24rpx;
							margin: 10rpx 0 0 52rpx;
						}
					}
					.sub-comment-item:last-child {
						margin-bottom: 0;
					}
				}
			}
		}
		.bottom-operate {
			.flex {
				display: flex;
				.home-icon {
					margin: 0 35rpx 0 20rpx;
				}
				.ico-box {
					text-align: center;
					.tui-skeleton-rect {
						line-height: 34rpx;
						background-color: #fff;
					}
					.icon-img {
						width: 52rpx;
						height: 52rpx;
						display: block;
					}
					.text {
						color: #666666;
						font-size: 18rpx;
					}
				}
			}
			.play-group {
				width: 408rpx;
			}
		}
	}
</style>

anchor.vue

同上anchor.vue

END...