| 
									
										
										
										
											2025-07-14 14:32:08 +08:00
										 |  |  |  | <template> | 
					
						
							|  |  |  |  |   <view class="default-share-page"> | 
					
						
							|  |  |  |  |     <!-- 背景图片,替代CSS background --> | 
					
						
							| 
									
										
										
										
											2025-10-10 16:29:28 +08:00
										 |  |  |  |     <img | 
					
						
							| 
									
										
										
										
											2025-07-14 14:32:08 +08:00
										 |  |  |  |       class="share-bg-image" | 
					
						
							| 
									
										
										
										
											2025-10-11 11:46:12 +08:00
										 |  |  |  |       src="@/static/images/share-bg.jpg" | 
					
						
							| 
									
										
										
										
											2025-07-14 14:32:08 +08:00
										 |  |  |  |       crossorigin="anonymous" | 
					
						
							|  |  |  |  |       @load="onBackgroundImageLoad" | 
					
						
							|  |  |  |  |       @error="onBackgroundImageError" | 
					
						
							| 
									
										
										
										
											2025-10-10 16:29:28 +08:00
										 |  |  |  |     /> | 
					
						
							| 
									
										
										
										
											2025-10-11 11:46:12 +08:00
										 |  |  |  |     <view class="qr-code-outer"> | 
					
						
							|  |  |  |  |       <image | 
					
						
							|  |  |  |  |         class="qr-code" | 
					
						
							|  |  |  |  |         :src="qrCodeImage" | 
					
						
							|  |  |  |  |         mode="aspectFit" | 
					
						
							|  |  |  |  |         v-if="qrCodeImage" | 
					
						
							|  |  |  |  |       ></image> | 
					
						
							|  |  |  |  |       <view v-else class="qr-code-placeholder"> | 
					
						
							|  |  |  |  |         <view class="loader"></view> | 
					
						
							| 
									
										
										
										
											2025-07-14 14:32:08 +08:00
										 |  |  |  |       </view> | 
					
						
							|  |  |  |  |     </view> | 
					
						
							| 
									
										
										
										
											2025-10-11 11:46:12 +08:00
										 |  |  |  |     <view class="member-code-outer"> | 
					
						
							|  |  |  |  |       <text | 
					
						
							|  |  |  |  |         class="member-code-text" | 
					
						
							|  |  |  |  |         style=" | 
					
						
							|  |  |  |  |           font-size: 20rpx; | 
					
						
							|  |  |  |  |           color: #fff; | 
					
						
							|  |  |  |  |           font-weight: bold; | 
					
						
							|  |  |  |  |           margin-top: 20rpx; | 
					
						
							|  |  |  |  |         " | 
					
						
							|  |  |  |  |         >{{ desensitization(userInfo.memberCode) }}</text | 
					
						
							|  |  |  |  |       > | 
					
						
							|  |  |  |  |     </view> | 
					
						
							| 
									
										
										
										
											2025-07-14 14:32:08 +08:00
										 |  |  |  |   </view> | 
					
						
							|  |  |  |  | </template> | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | <script> | 
					
						
							|  |  |  |  | import html2canvas from 'html2canvas' | 
					
						
							| 
									
										
										
										
											2025-10-11 11:46:12 +08:00
										 |  |  |  | import { snapdom } from '@zumer/snapdom' | 
					
						
							| 
									
										
										
										
											2025-07-14 14:32:08 +08:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  | export default { | 
					
						
							|  |  |  |  |   name: 'DefaultSharePage', | 
					
						
							|  |  |  |  |   props: { | 
					
						
							|  |  |  |  |     qrCodeImage: { | 
					
						
							|  |  |  |  |       type: String, | 
					
						
							|  |  |  |  |       default: '', | 
					
						
							|  |  |  |  |     }, | 
					
						
							|  |  |  |  |     userInfo: { | 
					
						
							|  |  |  |  |       type: Object, | 
					
						
							|  |  |  |  |       default: () => ({}), | 
					
						
							|  |  |  |  |     }, | 
					
						
							|  |  |  |  |     isWechat: { | 
					
						
							|  |  |  |  |       type: Boolean, | 
					
						
							|  |  |  |  |       default: false, | 
					
						
							|  |  |  |  |     }, | 
					
						
							|  |  |  |  |     isLoaded: { | 
					
						
							|  |  |  |  |       type: Boolean, | 
					
						
							|  |  |  |  |       default: false, | 
					
						
							|  |  |  |  |     }, | 
					
						
							|  |  |  |  |   }, | 
					
						
							|  |  |  |  |   data() { | 
					
						
							|  |  |  |  |     return { | 
					
						
							|  |  |  |  |       backgroundImageLoaded: false, | 
					
						
							|  |  |  |  |       shareButtonShow: true, | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  |   }, | 
					
						
							|  |  |  |  |   methods: { | 
					
						
							|  |  |  |  |     desensitization(str) { | 
					
						
							|  |  |  |  |       if (!str) return '' | 
					
						
							|  |  |  |  |       if (str.length <= 8) return str.slice(0, 4) + '****' | 
					
						
							|  |  |  |  |       const len = str.length - 6 | 
					
						
							|  |  |  |  |       const placeholder = '*'.repeat(len) | 
					
						
							|  |  |  |  |       return str.slice(0, 4) + placeholder + str.slice(-2) | 
					
						
							|  |  |  |  |     }, | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     // 背景图片加载成功
 | 
					
						
							|  |  |  |  |     onBackgroundImageLoad() { | 
					
						
							|  |  |  |  |       this.backgroundImageLoaded = true | 
					
						
							|  |  |  |  |       console.log('默认场景背景图片加载成功') | 
					
						
							|  |  |  |  |     }, | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     // 背景图片加载失败
 | 
					
						
							|  |  |  |  |     onBackgroundImageError(e) { | 
					
						
							|  |  |  |  |       console.error('默认场景背景图片加载失败:', e) | 
					
						
							|  |  |  |  |     }, | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     async sharePage() { | 
					
						
							|  |  |  |  |       if (!this.qrCodeImage) { | 
					
						
							|  |  |  |  |         uni.showToast({ | 
					
						
							|  |  |  |  |           title: '二维码尚未生成', | 
					
						
							|  |  |  |  |           icon: 'none', | 
					
						
							|  |  |  |  |         }) | 
					
						
							|  |  |  |  |         return | 
					
						
							|  |  |  |  |       } | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-10-11 11:46:12 +08:00
										 |  |  |  |       uni.showLoading({ title: '加载中...' }) | 
					
						
							| 
									
										
										
										
											2025-07-14 14:32:08 +08:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  |       try { | 
					
						
							|  |  |  |  |         this.shareButtonShow = false | 
					
						
							|  |  |  |  |         await this.$nextTick() | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |         await this.capturePageWithHtml2Canvas() | 
					
						
							|  |  |  |  |       } catch (error) { | 
					
						
							|  |  |  |  |         uni.hideLoading() | 
					
						
							|  |  |  |  |         uni.showToast({ title: '图片生成失败,请稍后重试', icon: 'none' }) | 
					
						
							|  |  |  |  |         console.error('sharePage error:', error) | 
					
						
							|  |  |  |  |       } finally { | 
					
						
							|  |  |  |  |         // 恢复按钮显示
 | 
					
						
							|  |  |  |  |         this.shareButtonShow = true | 
					
						
							|  |  |  |  |       } | 
					
						
							|  |  |  |  |     }, | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     // 使用html2canvas截取整个页面
 | 
					
						
							|  |  |  |  |     async capturePageWithHtml2Canvas() { | 
					
						
							|  |  |  |  |       console.log('开始使用html2canvas截取页面') | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |       return new Promise((resolve, reject) => { | 
					
						
							|  |  |  |  |         // 确保所有图片都已加载完成
 | 
					
						
							|  |  |  |  |         const waitForImages = () => { | 
					
						
							|  |  |  |  |           if (!this.backgroundImageLoaded || !this.qrCodeImage) { | 
					
						
							|  |  |  |  |             setTimeout(waitForImages, 100) | 
					
						
							|  |  |  |  |             return | 
					
						
							|  |  |  |  |           } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |           // 额外等待确保渲染完成
 | 
					
						
							|  |  |  |  |           setTimeout(() => { | 
					
						
							|  |  |  |  |             const element = this.$el | 
					
						
							|  |  |  |  |             if (!element) { | 
					
						
							|  |  |  |  |               reject(new Error('找不到组件容器')) | 
					
						
							|  |  |  |  |               return | 
					
						
							|  |  |  |  |             } | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-10-11 11:46:12 +08:00
										 |  |  |  |             const scale = 3 | 
					
						
							| 
									
										
										
										
											2025-07-14 14:32:08 +08:00
										 |  |  |  |             html2canvas(element, { | 
					
						
							|  |  |  |  |               useCORS: true, | 
					
						
							| 
									
										
										
										
											2025-10-11 11:46:12 +08:00
										 |  |  |  |               // allowTaint: true,
 | 
					
						
							| 
									
										
										
										
											2025-07-14 14:32:08 +08:00
										 |  |  |  |               backgroundColor: null, | 
					
						
							| 
									
										
										
										
											2025-10-11 11:46:12 +08:00
										 |  |  |  |               scale, | 
					
						
							|  |  |  |  |               // canvas,
 | 
					
						
							| 
									
										
										
										
											2025-07-14 14:32:08 +08:00
										 |  |  |  |               width: element.offsetWidth, | 
					
						
							|  |  |  |  |               height: element.offsetHeight, | 
					
						
							|  |  |  |  |             }) | 
					
						
							|  |  |  |  |               .then(canvas => { | 
					
						
							| 
									
										
										
										
											2025-10-11 11:46:12 +08:00
										 |  |  |  |                 const context = canvas.getContext('2d') | 
					
						
							|  |  |  |  |                 // context.scale(2, 2)
 | 
					
						
							|  |  |  |  |                 context.mozImageSmoothingEnabled = false | 
					
						
							|  |  |  |  |                 context.webkitImageSmoothingEnabled = false | 
					
						
							|  |  |  |  |                 context.msImageSmoothingEnabled = false | 
					
						
							|  |  |  |  |                 context.imageSmoothingEnabled = false | 
					
						
							| 
									
										
										
										
											2025-07-14 14:32:08 +08:00
										 |  |  |  |                 const dataUrl = canvas.toDataURL('image/jpeg', 1) | 
					
						
							|  |  |  |  |                 this.$emit('share-generated', dataUrl) | 
					
						
							|  |  |  |  |                 resolve() | 
					
						
							|  |  |  |  |               }) | 
					
						
							|  |  |  |  |               .catch(err => { | 
					
						
							|  |  |  |  |                 console.error('html2canvas截取失败:', err) | 
					
						
							|  |  |  |  |                 reject(err) | 
					
						
							|  |  |  |  |               }) | 
					
						
							|  |  |  |  |           }, 1000) | 
					
						
							|  |  |  |  |         } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |         // 开始等待图片加载
 | 
					
						
							|  |  |  |  |         waitForImages() | 
					
						
							|  |  |  |  |       }) | 
					
						
							|  |  |  |  |     }, | 
					
						
							|  |  |  |  |   }, | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | </script> | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | <style lang="scss" scoped> | 
					
						
							|  |  |  |  | .default-share-page { | 
					
						
							|  |  |  |  |   position: relative; | 
					
						
							| 
									
										
										
										
											2025-10-10 16:29:28 +08:00
										 |  |  |  |   width: 600rpx; | 
					
						
							| 
									
										
										
										
											2025-10-11 11:46:12 +08:00
										 |  |  |  |   height: 1296rpx; | 
					
						
							|  |  |  |  |   // height: 100%;
 | 
					
						
							| 
									
										
										
										
											2025-07-14 14:32:08 +08:00
										 |  |  |  |   display: flex; | 
					
						
							|  |  |  |  |   flex-direction: column; | 
					
						
							|  |  |  |  |   align-items: center; | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | /* 背景图片样式 */ | 
					
						
							|  |  |  |  | .share-bg-image { | 
					
						
							|  |  |  |  |   position: absolute; | 
					
						
							|  |  |  |  |   top: 0; | 
					
						
							|  |  |  |  |   left: 0; | 
					
						
							| 
									
										
										
										
											2025-10-10 16:29:28 +08:00
										 |  |  |  |   width: 600rpx; | 
					
						
							| 
									
										
										
										
											2025-10-11 11:46:12 +08:00
										 |  |  |  |   height: 1296rpx; | 
					
						
							|  |  |  |  |   // height: 100%;
 | 
					
						
							| 
									
										
										
										
											2025-07-14 14:32:08 +08:00
										 |  |  |  |   z-index: 1; | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | .share-wrapper { | 
					
						
							|  |  |  |  |   position: absolute; | 
					
						
							|  |  |  |  |   z-index: 2; | 
					
						
							| 
									
										
										
										
											2025-10-11 11:46:12 +08:00
										 |  |  |  |   bottom: 22%; | 
					
						
							| 
									
										
										
										
											2025-07-14 14:32:08 +08:00
										 |  |  |  |   display: flex; | 
					
						
							|  |  |  |  |   flex-direction: column; | 
					
						
							|  |  |  |  |   align-items: center; | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | .portal-frame { | 
					
						
							| 
									
										
										
										
											2025-10-11 11:46:12 +08:00
										 |  |  |  |   padding: 32rpx; | 
					
						
							|  |  |  |  |   width: 520rpx; | 
					
						
							| 
									
										
										
										
											2025-07-14 14:32:08 +08:00
										 |  |  |  |   border-radius: 40rpx; | 
					
						
							|  |  |  |  |   display: flex; | 
					
						
							|  |  |  |  |   box-sizing: border-box; | 
					
						
							|  |  |  |  |   flex-direction: column; | 
					
						
							|  |  |  |  |   align-items: center; | 
					
						
							|  |  |  |  |   margin: 0 auto; | 
					
						
							|  |  |  |  |   opacity: 0; | 
					
						
							|  |  |  |  |   transform: translateY(20rpx); | 
					
						
							|  |  |  |  |   transition: all 0.3s ease; | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | .portal-frame.is-loaded { | 
					
						
							|  |  |  |  |   opacity: 1; | 
					
						
							|  |  |  |  |   transform: translateY(0); | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | /* 二维码样式区域 - 用户自定义样式位置 */ | 
					
						
							|  |  |  |  | .qr-code-outer { | 
					
						
							| 
									
										
										
										
											2025-10-11 11:46:12 +08:00
										 |  |  |  |   width: 140rpx; | 
					
						
							|  |  |  |  |   height: 140rpx; | 
					
						
							|  |  |  |  |   background: rgba(255, 255, 255, 0.98); | 
					
						
							| 
									
										
										
										
											2025-07-14 14:32:08 +08:00
										 |  |  |  |   border-radius: 20rpx; | 
					
						
							| 
									
										
										
										
											2025-10-11 11:46:12 +08:00
										 |  |  |  |   box-shadow: 0px 8rpx 20rpx rgba(50, 50, 90, 0.06); | 
					
						
							|  |  |  |  |   border: 1px solid #f0f0f0; | 
					
						
							| 
									
										
										
										
											2025-07-14 14:32:08 +08:00
										 |  |  |  |   display: flex; | 
					
						
							|  |  |  |  |   align-items: center; | 
					
						
							|  |  |  |  |   justify-content: center; | 
					
						
							|  |  |  |  |   padding: 12rpx; | 
					
						
							|  |  |  |  |   box-sizing: border-box; | 
					
						
							| 
									
										
										
										
											2025-10-11 11:46:12 +08:00
										 |  |  |  |   position: absolute; | 
					
						
							|  |  |  |  |   // bottom: 460rpx;
 | 
					
						
							|  |  |  |  |   left: 374rpx; | 
					
						
							|  |  |  |  |   top: 708rpx; | 
					
						
							|  |  |  |  |   // right: 130rpx;
 | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   z-index: 10; | 
					
						
							| 
									
										
										
										
											2025-07-14 14:32:08 +08:00
										 |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | .qr-code, | 
					
						
							|  |  |  |  | .qr-code-placeholder { | 
					
						
							|  |  |  |  |   width: 100%; | 
					
						
							|  |  |  |  |   height: 100%; | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | .qr-code { | 
					
						
							|  |  |  |  |   border-radius: 16rpx; | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | .qr-code-placeholder { | 
					
						
							|  |  |  |  |   display: flex; | 
					
						
							|  |  |  |  |   align-items: center; | 
					
						
							|  |  |  |  |   justify-content: center; | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | .loader { | 
					
						
							|  |  |  |  |   width: 100rpx; | 
					
						
							|  |  |  |  |   height: 100rpx; | 
					
						
							|  |  |  |  |   border: 8rpx solid rgba(0, 0, 0, 0.1); | 
					
						
							|  |  |  |  |   border-left-color: #0072ff; | 
					
						
							|  |  |  |  |   border-radius: 50%; | 
					
						
							|  |  |  |  |   animation: spin 1s linear infinite; | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | @keyframes spin { | 
					
						
							|  |  |  |  |   to { | 
					
						
							|  |  |  |  |     transform: rotate(360deg); | 
					
						
							|  |  |  |  |   } | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | /* 会员编号样式区域 - 用户自定义样式位置 */ | 
					
						
							|  |  |  |  | .member-code-text { | 
					
						
							| 
									
										
										
										
											2025-10-11 11:46:12 +08:00
										 |  |  |  |   /* 用户可以在这里自定义会员编号的样式 */ | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | .member-code-outer { | 
					
						
							|  |  |  |  |   position: absolute; | 
					
						
							|  |  |  |  |   top: 1086rpx; | 
					
						
							|  |  |  |  |   left: 246rpx; | 
					
						
							|  |  |  |  |   // width: 300rpx;
 | 
					
						
							|  |  |  |  |   text-align: center; | 
					
						
							|  |  |  |  |   // background: rgb(217, 24, 25);
 | 
					
						
							|  |  |  |  |   border-radius: 20rpx; | 
					
						
							|  |  |  |  |   z-index: 10; | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | /* 下载按钮样式 */ | 
					
						
							|  |  |  |  | .share-button { | 
					
						
							|  |  |  |  |   margin-top: 28rpx; | 
					
						
							|  |  |  |  |   width: 280rpx; | 
					
						
							|  |  |  |  |   height: 72rpx; | 
					
						
							|  |  |  |  |   line-height: 72rpx; | 
					
						
							|  |  |  |  |   color: #fff; | 
					
						
							|  |  |  |  |   border-radius: 36rpx; | 
					
						
							|  |  |  |  |   font-size: 26rpx; | 
					
						
							|  |  |  |  |   font-weight: 500; | 
					
						
							|  |  |  |  |   background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); | 
					
						
							|  |  |  |  |   box-shadow: 0 5rpx 12rpx 0 rgba(102, 126, 234, 0.2); | 
					
						
							|  |  |  |  |   border: none; | 
					
						
							|  |  |  |  |   padding: 0; | 
					
						
							|  |  |  |  |   text-align: center; | 
					
						
							|  |  |  |  |   transition: all 0.3s ease; | 
					
						
							|  |  |  |  |   letter-spacing: 1rpx; | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | button.share-button { | 
					
						
							|  |  |  |  |   padding: 0; | 
					
						
							|  |  |  |  |   line-height: 72rpx; | 
					
						
							|  |  |  |  |   border: none; | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | .share-button:active { | 
					
						
							|  |  |  |  |   transform: translateY(1rpx); | 
					
						
							|  |  |  |  |   box-shadow: 0 4rpx 10rpx rgba(102, 126, 234, 0.4); | 
					
						
							|  |  |  |  |   background: linear-gradient(135deg, #5a67d8 0%, #6b46c1 100%); | 
					
						
							| 
									
										
										
										
											2025-07-14 14:32:08 +08:00
										 |  |  |  | } | 
					
						
							|  |  |  |  | </style> |